1 /* ----------------------------------------------------------------------------------------------- */
2 /* MHash-384 - Generate tables utility program */
3 /* Copyright(c) 2016-2017 LoRd_MuldeR <mulder2@gmx.de> */
5 /* Permission is hereby granted, free of charge, to any person obtaining a copy of this software */
6 /* and associated documentation files(the "Software"), to deal in the Software without */
7 /* restriction, including without limitation the rights to use, copy, modify, merge, publish, */
8 /* distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the */
9 /* Software is furnished to do so, subject to the following conditions: */
11 /* The above copyright notice and this permission notice shall be included in all copies or */
12 /* substantial portions of the Software. */
14 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING */
15 /* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
16 /* NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, */
17 /* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
18 /* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
19 /* ----------------------------------------------------------------------------------------------- */
22 #include "thread_utils.h"
24 #include "boxmuller.h"
36 //-----------------------------------------------------------------------------
38 //-----------------------------------------------------------------------------
41 #define DISTANCE_MIN 182U
43 #define THREAD_COUNT 8U
48 #define ROW_NUM (UINT8_MAX+2) /*total number of rows*/
49 #define ROW_LEN (HASH_LEN / CHAR_BIT) /*number of bits per row*/
51 #define __DISTANCE_STR(X) #X
52 #define _DISTANCE_STR(X) __DISTANCE_STR(X)
53 #define DISTANCE_STR _DISTANCE_STR(DISTANCE_MIN)
55 #define MAGIC_NUMBER 0x3C6058A7C1132CB2ui64
56 #define THREAD_ID (pthread_getw32threadid_np(pthread_self()))
58 //-----------------------------------------------------------------------------
60 //-----------------------------------------------------------------------------
62 static uint8_t g_table[ROW_NUM][ROW_LEN];
63 static uint8_t g_thread_buffer[THREAD_COUNT][ROW_LEN];
65 static size_t g_spinpos = 0;
66 static char SPINNER[4] = { '/', '-', '\\', '|' };
69 static volatile long long g_stat_too_hi = 0i64;
70 static volatile long long g_stat_too_lo = 0i64;
73 //-----------------------------------------------------------------------------
75 //-----------------------------------------------------------------------------
78 #define TRACE(X, ...) printf("[%04X] " X "\n", THREAD_ID, __VA_ARGS__)
80 #define TRACE(X, ...) __noop()
83 static inline void print_row(uint8_t *const row_buffer)
85 for (size_t w = 0; w < ROW_LEN; ++w)
87 printf("%02X", row_buffer[w]);
92 static inline void flip_bit_at(uint8_t *const row_buffer, const size_t pos)
94 row_buffer[pos >> 3] ^= ((uint8_t)(1U << (pos & 0x7)));
97 static inline void flip_rand_n(uint8_t *const row_buffer, twister_t *const rand, const uint32_t n)
100 memset(&taken, 0, sizeof(bool) * HASH_LEN);
101 for (uint32_t i = 0; i < n; ++i)
106 next = next_rand_range(rand, HASH_LEN);
109 flip_bit_at(row_buffer, next);
114 static inline bool check_distance_rows(const uint32_t distance_max, const size_t index_1, const size_t index_2)
116 const uint32_t dist = hamming_distance(&g_table[index_1][0], &g_table[index_2][0], ROW_LEN);
117 return (dist <= distance_max) && (dist >= DISTANCE_MIN);
120 static inline uint32_t check_distance_buff(const uint32_t distance_max, const size_t index, const uint8_t *const row_buffer, const uint32_t limit)
125 #endif //ENABLE_STATS
126 for (size_t k = 0; k < index; k++)
129 const uint32_t dist = hamming_distance(&g_table[k][0], row_buffer, ROW_LEN);
130 if (dist > distance_max)
132 const uint32_t current = dist - distance_max;
137 #endif //ENABLE_STATS
138 if ((error = current) >= limit)
140 break; /*early termination*/
144 else if (dist < DISTANCE_MIN)
146 const uint32_t current = DISTANCE_MIN - dist;
151 #endif //ENABLE_STATS
152 if ((error = current) >= limit)
154 break; /*early termination*/
160 _InterlockedIncrement64(reason ? &g_stat_too_lo : &g_stat_too_hi);
161 #endif //ENABLE_STATS
165 static dump_table(FILE *out)
167 fputs("uint8_t MHASH_384_TABLE_XOR[UINT8_MAX+2][MHASH_384_LEN] =\n{\n", out);
168 for (size_t i = 0; i < ROW_NUM; i++)
171 for (size_t j = 0; j < ROW_LEN; j++)
177 fprintf(out, "0x%02X", g_table[i][j]);
179 fprintf(out, " }%s /*%02X*/\n", (i != (ROW_NUM - 1)) ? "," : " ", (uint32_t)(i % 0x100));
184 //-----------------------------------------------------------------------------
186 //-----------------------------------------------------------------------------
193 pthread_mutex_t *mutex;
194 volatile long *distance_max;
198 static void* thread_main(void *const param)
200 const thread_data_t *const data = ((const thread_data_t*)param);
203 uint8_t temp[ROW_LEN];
206 const uint32_t distance_max = (uint32_t)*data->distance_max;
207 TRACE("Maximum distance: %u", distance_max);
208 rand_init(&rand, make_seed());
209 gaussian_noise_init(&bxmller);
210 rand_next_bytes(&rand, data->row_buffer, ROW_LEN);
211 uint32_t error = check_distance_buff(distance_max, data->index, data->row_buffer, HASH_LEN);
214 for (int32_t round = 0; round < 4999; ++round)
216 if (!(round & 0x3FF))
218 if (SEM_TRYWAIT(data->stop))
223 for (size_t rand_loop = 0; rand_loop < 99991U; ++rand_loop)
225 rand_next_bytes(&rand, temp, ROW_LEN);
226 const uint32_t next_error = check_distance_buff(distance_max, data->index, temp, error);
227 if (next_error < error)
230 memcpy(data->row_buffer, temp, sizeof(uint8_t) * ROW_LEN);
231 if (!((error = next_error) > 0U))
233 TRACE("Success by rand-init <<<---");
239 for (int32_t round = 0; round < 743; ++round)
241 TRACE("Optimizer round %u of 743", round);
244 for (size_t xchg_pos = 0U; xchg_pos < ROW_LEN; ++xchg_pos)
246 uint8_t value = (uint8_t) rand_next_uint(&rand);
247 uint8_t original = data->row_buffer[xchg_pos];
248 for (size_t xchg_cnt = 0U; xchg_cnt <= UINT8_MAX; ++xchg_cnt, ++value)
250 data->row_buffer[xchg_pos] = value;
251 const uint32_t next_error = check_distance_buff(distance_max, data->index, data->row_buffer, error);
252 if (next_error < error)
254 TRACE("Improved by xchg-byte");
257 if (!((error = next_error) > 0U))
259 TRACE("Success by xchg-byte <<<---");
264 data->row_buffer[xchg_pos] = original;
266 for (size_t flip_pos_w = 0U; flip_pos_w < HASH_LEN; ++flip_pos_w)
268 if (SEM_TRYWAIT(data->stop))
272 flip_bit_at(data->row_buffer, flip_pos_w);
273 bool revert_w = true;
274 const uint32_t next_error = check_distance_buff(distance_max, data->index, data->row_buffer, error);
275 if (next_error < error)
277 TRACE("Improved by flip-1");
280 if (!((error = next_error) > 0U))
282 TRACE("success by flip-1 <<<---");
286 for (size_t flip_pos_x = flip_pos_w + 1U; flip_pos_x < HASH_LEN; ++flip_pos_x)
288 flip_bit_at(data->row_buffer, flip_pos_x);
289 bool revert_x = true;
290 const uint32_t next_error = check_distance_buff(distance_max, data->index, data->row_buffer, error);
291 if (next_error < error)
293 TRACE("Improved by flip-2");
297 if (!((error = next_error) > 0U))
299 TRACE("success by flip-2 <<<---");
303 for (size_t flip_pos_y = flip_pos_x + 1U; flip_pos_y < HASH_LEN; ++flip_pos_y)
305 flip_bit_at(data->row_buffer, flip_pos_y);
306 bool revert_y = true;
307 const uint32_t next_error = check_distance_buff(distance_max, data->index, data->row_buffer, error);
308 if (next_error < error)
310 TRACE("Improved by flip-3");
315 if (!((error = next_error) > 0U))
317 TRACE("success by flip-3 <<<---");
321 for (size_t flip_pos_z = flip_pos_y + 1U; flip_pos_z < HASH_LEN; ++flip_pos_z)
323 flip_bit_at(data->row_buffer, flip_pos_z);
324 const uint32_t next_error = check_distance_buff(distance_max, data->index, data->row_buffer, error);
325 if (next_error < error)
327 TRACE("Improved by flip-4");
332 if (!((error = next_error) > 0U))
334 TRACE("success by flip-4 <<<---");
340 flip_bit_at(data->row_buffer, flip_pos_z);
345 flip_bit_at(data->row_buffer, flip_pos_y);
350 flip_bit_at(data->row_buffer, flip_pos_x);
355 flip_bit_at(data->row_buffer, flip_pos_w);
359 for (size_t rand_mode = 0; rand_mode < 4U; ++rand_mode)
361 memcpy(temp, &data->row_buffer, sizeof(uint8_t) * ROW_LEN);
362 for (size_t rand_loop = 0; rand_loop < 12007U; ++rand_loop)
367 rand_next_bytes(&rand, &temp[0U], ROW_LEN / 2U);
370 rand_next_bytes(&rand, &temp[ROW_LEN / 2U], ROW_LEN / 2U);
373 rand_next_bytes(&rand, &temp[0U], ROW_LEN / 4U);
374 rand_next_bytes(&rand, &temp[ROW_LEN / 2U], ROW_LEN / 4U);
377 rand_next_bytes(&rand, &temp[ROW_LEN / 4U], ROW_LEN / 4U);
378 rand_next_bytes(&rand, &temp[3U * (ROW_LEN / 4U)], ROW_LEN / 4U);
383 const uint32_t next_error = check_distance_buff(distance_max, data->index, temp, error);
384 if (next_error < error)
386 TRACE("Improved by rand-replace #%zu", rand_mode);
388 memcpy(data->row_buffer, temp, sizeof(uint8_t) * ROW_LEN);
389 if (!((error = next_error) > 0U))
391 TRACE("Success by rand-replace <<<---");
397 for (size_t refine_loop = 0; refine_loop < 9973U; ++refine_loop)
399 if (!(refine_loop & 0x3FF))
401 if (SEM_TRYWAIT(data->stop))
406 const uint32_t flip_count = gaussian_noise_next(&rand, &bxmller, 3.14159, 5U, HASH_LEN);
407 for (size_t refine_step = 0; refine_step < 997U; ++refine_step)
409 memcpy(temp, data->row_buffer, sizeof(uint8_t) * ROW_LEN);
410 flip_rand_n(temp, &rand, flip_count);
411 const uint32_t next_error = check_distance_buff(distance_max, data->index, temp, error);
412 if (next_error < error)
414 TRACE("Improved by rand-flip (%u)", flip_count);
416 memcpy(data->row_buffer, temp, sizeof(uint8_t) * ROW_LEN);
417 if (!((error = next_error) > 0U))
419 TRACE("Success by rand-flip (%u) <<<---", flip_count);
427 _InterlockedCompareExchange(data->distance_max, min(distance_max + 1U, HASH_LEN), distance_max);
436 if (check_distance_buff(*data->distance_max, data->index, data->row_buffer, HASH_LEN))
438 fprintf(stderr, "ERROR MISCOMPARE!\n");
442 MUTEX_LOCK(data->mutex);
443 if (SEM_TRYWAIT(data->stop))
445 MUTEX_UNLOCK(data->mutex);
449 SEM_POST(data->stop, THREAD_COUNT);
450 MUTEX_UNLOCK(data->mutex);
451 return data->row_buffer; /*success*/
454 static void* thread_spin(void *const param)
456 unsigned long delay = 1U;
457 sem_t *const stop = ((sem_t*)param);
460 if (SEM_TRYWAIT(stop))
469 const long long s_too_lo = g_stat_too_lo, s_too_hi = g_stat_too_hi;
470 const long long s_too_ac = s_too_lo + s_too_hi;
471 printf("Too low: %lld (%.2f), too high: %lld (%.2f)\n", s_too_lo, s_too_lo / ((double)s_too_ac), s_too_hi, s_too_hi / ((double)s_too_ac));
472 #endif //ENABLE_STATS
473 printf("\b\b\b[%c]", SPINNER[g_spinpos]);
474 g_spinpos = (g_spinpos + 1) % 4;
483 //-----------------------------------------------------------------------------
485 //-----------------------------------------------------------------------------
487 static bool save_table_data(const wchar_t *const filename, const size_t rows_completed_in, const uint32_t current_dist_max)
489 wchar_t filename_temp[_MAX_PATH];
490 swprintf_s(filename_temp, _MAX_PATH, L"%s~%X", filename, make_seed());
491 FILE *const file = _wfopen(filename_temp, L"wb");
495 const uint64_t magic_number = MAGIC_NUMBER;
496 const uint32_t hash_len = HASH_LEN, distance_min = DISTANCE_MIN, distance_max = current_dist_max, rows_completed = (uint32_t)rows_completed_in;
497 fwrite(&magic_number, sizeof(uint64_t), 1, file);
498 fwrite(&hash_len, sizeof(uint32_t), 1, file);
499 fwrite(&distance_min, sizeof(uint32_t), 1, file);
500 fwrite(&distance_max, sizeof(uint32_t), 1, file);
501 fwrite(&rows_completed, sizeof(uint32_t), 1, file);
502 for (uint32_t i = 0; i < rows_completed; ++i)
504 const uint32_t checksum = adler32(&g_table[i][0], ROW_LEN);
505 fwrite(&checksum, sizeof(uint32_t), 1, file);
506 fwrite(&g_table[i][0], sizeof(uint8_t), ROW_LEN, file);
510 printf("ERROR: Failed to write table data!\n");
516 for (size_t i = 0; i < 42; ++i)
518 if (_wremove(filename))
522 printf("ERROR: Failed to delete existing file!\n");
529 if (_wrename(filename_temp, filename))
531 printf("ERROR: Failed to rename temp file!\n");
537 _wremove(filename_temp);
543 printf("ERROR: Failed to open table file for writing!\n");
548 static bool load_table_data(const wchar_t *const filename, size_t *const rows_completed_out, volatile long *const dist_max_out)
550 FILE *const file = _wfopen(filename, L"rb");
554 uint64_t magic_number;
555 uint32_t hash_len, distance_min, distance_max, rows_completed;
556 fread(&magic_number, sizeof(uint64_t), 1, file);
557 fread(&hash_len, sizeof(uint32_t), 1, file);
558 fread(&distance_min, sizeof(uint32_t), 1, file);
559 fread(&distance_max, sizeof(uint32_t), 1, file);
560 fread(&rows_completed, sizeof(uint32_t), 1, file);
561 if (ferror(file) || feof(file))
563 printf("ERROR: Failed to read the table header!\n");
567 if (magic_number != MAGIC_NUMBER)
569 printf("ERROR: Table file format could not be recognized!\n");
573 if ((hash_len != HASH_LEN) || (distance_min != DISTANCE_MIN) || (distance_max > HASH_LEN) || (rows_completed > ROW_NUM))
575 printf("ERROR: Table properties are incompatibe with this instance!\n");
579 for (size_t i = 0; i < rows_completed; ++i)
581 uint32_t checksum_expected;
582 if ((fread(&checksum_expected, sizeof(uint32_t), 1, file) != 1) || (fread(&g_table[i][0], sizeof(uint8_t), ROW_LEN, file) != ROW_LEN))
584 printf("ERROR: Failed to read table data from file!\n");
588 if (adler32(&g_table[i][0], ROW_LEN) != checksum_expected)
590 printf("ERROR: Table checksum does *not* match table contents!\n");
594 for (size_t j = 0; j < i; j++)
596 if (!check_distance_rows(distance_max, i, j))
598 printf("ERROR: Table distance verification has failed!\n");
606 if (success && rows_completed_out)
608 *rows_completed_out = (size_t)rows_completed;
609 *dist_max_out = (long)distance_max;
615 printf("ERROR: Failed to open table file for reading!\n");
620 //-----------------------------------------------------------------------------
622 //-----------------------------------------------------------------------------
624 int wmain(int argc, wchar_t *argv[])
626 pthread_t thread_id[THREAD_COUNT + 1];
627 thread_data_t thread_data[THREAD_COUNT];
629 pthread_mutex_t stop_mutex;
630 FILE *file_out = NULL;
631 size_t initial_row_index = 0;
632 volatile long distance_max = DISTANCE_MIN;
634 printf("MHash GenTableXOR [%s]\n\n", __DATE__);
635 printf("HashLen: %d, Distance Min: %d, Threads: %d\n\n", HASH_LEN, DISTANCE_MIN, THREAD_COUNT);
637 if ((HASH_LEN % (8 * sizeof(uint32_t))) != 0)
639 crit_exit("FATAL: Hash length must be a multiple of 32 bits!");
644 printf("Table file not specified!\n\n");
646 printf(" GenTables_XOR.exe <table_file>\n\n");
650 for (size_t i = 0; i < ROW_NUM; i++)
652 memset(&g_table[i][0], 0, sizeof(uint8_t) * ROW_LEN);
655 memset(&thread_id, 0, sizeof(pthread_t) * (THREAD_COUNT + 1));
656 memset(&thread_data, 0, sizeof(thread_data_t) * THREAD_COUNT);
657 for (size_t t = 0; t < THREAD_COUNT; t++)
659 memset(&g_thread_buffer[t][0], 0, sizeof(uint8_t) * ROW_LEN);
662 SEM_INIT(&stop_flag);
663 MUTEX_INIT(&stop_mutex);
665 if (_waccess(argv[1], 4) == 0)
667 printf("Loading existing table data and proceeding...\n");
668 if (!load_table_data(argv[1], &initial_row_index, &distance_max))
674 for (size_t i = initial_row_index; i < ROW_NUM; i++)
676 char time_string[64];
677 printf("\aRow %03u of %03u [%c]", (uint32_t)(i+1U), ROW_NUM, SPINNER[g_spinpos]);
678 g_spinpos = (g_spinpos + 1) % 4;
680 g_stat_too_hi = g_stat_too_lo = 0i64;
681 #endif //INCREMENT_STAT
683 PTHREAD_CREATE(&thread_id[THREAD_COUNT], NULL, thread_spin, &stop_flag);
684 for (size_t t = 0; t < THREAD_COUNT; t++)
686 thread_data[t].index = i;
687 thread_data[t].row_buffer = &g_thread_buffer[t][0];
688 thread_data[t].stop = &stop_flag;
689 thread_data[t].mutex = &stop_mutex;
690 thread_data[t].distance_max = &distance_max;
691 PTHREAD_CREATE(&thread_id[t], NULL, thread_main, &thread_data[t]);
692 PTHREAD_SET_PRIORITY(thread_id[t], -15);
695 for (size_t t = 0; t < THREAD_COUNT; t++)
697 void *return_value = NULL;
698 PTHREAD_JOIN(thread_id[t], &return_value);
701 memcpy(&g_table[i][0], return_value, sizeof(uint8_t) * ROW_LEN);
705 PTHREAD_JOIN(thread_id[THREAD_COUNT], NULL);
706 get_time_str(time_string, 64);
707 printf("\b\b\b[#] - %s\n", time_string);
709 if (!save_table_data(argv[1], i + 1U, distance_max))
711 return 1; /*failed to save current table data*/
715 printf("\n-----\n\n");
718 if (fopen_s(&file_out, "table_XOR." DISTANCE_STR ".txt", "w") == 0)
720 dump_table(file_out);
724 printf("\n-----\n\n");
726 for (size_t i = 0; i < ROW_NUM; i++)
728 for (size_t j = 0; j < ROW_NUM; j++)
734 if (!check_distance_rows(distance_max, i, j))
736 crit_exit("FATAL: Table verification has failed!");
741 SEM_DESTROY(&stop_flag);
742 MUTEX_DESTROY(&stop_mutex);
744 printf("COMPLETED.\n\n");
745 system("shutdown /s /t 180");