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"
35 //-----------------------------------------------------------------------------
37 //-----------------------------------------------------------------------------
40 #define DISTANCE_MIN 190U
42 #define THREAD_COUNT 8U
46 #define ROW_NUM (UINT8_MAX+2) /*total number of rows*/
47 #define ROW_LEN (HASH_LEN / CHAR_BIT) /*number of bits per row*/
49 #define __DISTANCE_STR(X) #X
50 #define _DISTANCE_STR(X) __DISTANCE_STR(X)
51 #define DISTANCE_STR _DISTANCE_STR(DISTANCE_MIN)
53 #define MAGIC_NUMBER 0x3C6058A7C1132CB2ui64
54 #define THREAD_ID (pthread_getw32threadid_np(pthread_self()))
56 //-----------------------------------------------------------------------------
58 //-----------------------------------------------------------------------------
60 static uint8_t g_table[ROW_NUM][ROW_LEN];
61 static uint8_t g_thread_buffer[THREAD_COUNT][ROW_LEN];
63 static const char SPINNER[4] = { '/', '-', '\\', '|' };
64 static const double SQRT2 = 1.41421356237309504880168872420969807856967187537694;
66 static size_t g_spinpos = 0;
68 //-----------------------------------------------------------------------------
70 //-----------------------------------------------------------------------------
73 #define TRACE(X, ...) printf("[%04X] " X "\n", THREAD_ID, __VA_ARGS__)
75 #define TRACE(X, ...) __noop()
78 static inline void print_row(uint8_t *const row_buffer)
80 for (size_t w = 0; w < ROW_LEN; ++w)
82 printf("%02X", row_buffer[w]);
87 static inline void flip_bit_at(uint8_t *const row_buffer, const size_t pos)
89 row_buffer[pos >> 3] ^= ((uint8_t)(1U << (pos & 0x7)));
92 static inline void flip_rand_n(uint8_t *const row_buffer, msws_t rand, const uint32_t n)
95 memset(&taken, 0, sizeof(bool) * HASH_LEN);
96 for (uint_fast32_t i = 0; i < n; ++i)
101 next = msws_uint32_max(rand, HASH_LEN);
104 flip_bit_at(row_buffer, next);
109 static inline bool check_distance_rows(const uint_fast32_t distance_max, const size_t index_1, const size_t index_2)
111 const uint_fast32_t dist = hamming_distance(&g_table[index_1][0], &g_table[index_2][0], ROW_LEN);
112 return (dist <= distance_max) && (dist >= DISTANCE_MIN);
115 #define ERROR_ACC(MAX,ACC) (((MAX) << 20U) | (ACC))
116 static inline uint_fast32_t check_distance_buff(const uint_fast32_t distance_max, const size_t index, const uint8_t *const row_buffer, const uint32_t limit)
118 uint_fast32_t error_max = 0U, error_acc = 0U;
119 for (size_t k = 0; k < index; k++)
121 const uint_fast32_t dist = hamming_distance(&g_table[k][0], row_buffer, ROW_LEN);
122 if (dist > distance_max)
124 const uint_fast32_t current = dist - distance_max;
125 error_acc += current;
126 if (current > error_max)
130 if (ERROR_ACC(error_max, error_acc) >= limit)
132 break; /*early termination*/
135 else if (dist < DISTANCE_MIN)
137 const uint_fast32_t current = DISTANCE_MIN - dist;
138 error_acc += current;
139 if (current > error_max)
143 if (ERROR_ACC(error_max, error_acc) >= limit)
145 break; /*early termination*/
149 return ERROR_ACC(error_max, error_acc);
152 static void dump_table(FILE *out)
154 fputs("uint8_t MHASH_384_TABLE_XOR[UINT8_MAX+2][MHASH_384_LEN] =\n{\n", out);
155 for (size_t i = 0; i < ROW_NUM; i++)
158 for (size_t j = 0; j < ROW_LEN; j++)
164 fprintf(out, "0x%02X", g_table[i][j]);
166 fprintf(out, " }%s /*%02X*/\n", (i != (ROW_NUM - 1)) ? "," : " ", (uint32_t)(i % 0x100));
171 //-----------------------------------------------------------------------------
173 //-----------------------------------------------------------------------------
180 pthread_mutex_t *mutex;
181 uint_fast32_t distance_max;
185 static void* thread_main(void *const param)
187 thread_data_t *const data = (thread_data_t*)param;
190 uint8_t temp[ROW_LEN];
193 TRACE("Maximum distance: %u", data->distance_max);
194 msws_init(rand, make_seed());
195 gaussian_noise_init(&bxmller);
196 msws_bytes(rand, data->row_buffer, ROW_LEN);
197 uint_fast32_t error = check_distance_buff(data->distance_max, data->index, data->row_buffer, HASH_LEN);
200 for (int_fast16_t round = 0; round < 29989; ++round)
202 if (!(round & 0x3FF))
204 if (SEM_TRYWAIT(data->stop))
209 for (uint_fast16_t rand_loop = 0; rand_loop < 99991U; ++rand_loop)
211 msws_bytes(rand, temp, ROW_LEN);
212 const uint_fast32_t next_error = check_distance_buff(data->distance_max, data->index, temp, error);
213 if (next_error < error)
215 TRACE("Improved by rand-init (%08X -> %08X)", error, next_error);
217 memcpy(data->row_buffer, temp, sizeof(uint8_t) * ROW_LEN);
218 if (!((error = next_error) > 0U))
220 TRACE("Success by rand-init <<<---");
226 for (int_fast16_t round = 0; round < 997; ++round)
228 TRACE("Optimizer round %u of 997", round + 1);
231 for (uint_fast16_t xchg_pos = 0U; xchg_pos < ROW_LEN; ++xchg_pos)
233 uint8_t value = (uint8_t)msws_uint32(rand);
234 uint8_t original = data->row_buffer[xchg_pos];
235 for (uint_fast16_t xchg_cnt = 0U; xchg_cnt <= UINT8_MAX; ++xchg_cnt, ++value)
237 data->row_buffer[xchg_pos] = value;
238 const uint_fast32_t next_error = check_distance_buff(data->distance_max, data->index, data->row_buffer, error);
239 if (next_error < error)
241 TRACE("Improved by xchg-byte (%08X -> %08X)", error, next_error);
244 if (!((error = next_error) > 0U))
246 TRACE("Success by xchg-byte <<<---");
251 data->row_buffer[xchg_pos] = original;
253 for (uint_fast16_t flip_pos_w = 0U; flip_pos_w < HASH_LEN; ++flip_pos_w)
255 if (SEM_TRYWAIT(data->stop))
259 flip_bit_at(data->row_buffer, flip_pos_w);
260 bool revert_w = true;
261 const uint_fast32_t next_error = check_distance_buff(data->distance_max, data->index, data->row_buffer, error);
262 if (next_error < error)
264 TRACE("Improved by flip-1 (%08X -> %08X)", error, next_error);
267 if (!((error = next_error) > 0U))
269 TRACE("success by flip-1 <<<---");
273 for (uint_fast16_t flip_pos_x = flip_pos_w + 1U; flip_pos_x < HASH_LEN; ++flip_pos_x)
275 flip_bit_at(data->row_buffer, flip_pos_x);
276 bool revert_x = true;
277 const uint_fast32_t next_error = check_distance_buff(data->distance_max, data->index, data->row_buffer, error);
278 if (next_error < error)
280 TRACE("Improved by flip-2 (%08X -> %08X)", error, next_error);
284 if (!((error = next_error) > 0U))
286 TRACE("success by flip-2 <<<---");
290 for (uint_fast16_t flip_pos_y = flip_pos_x + 1U; flip_pos_y < HASH_LEN; ++flip_pos_y)
292 flip_bit_at(data->row_buffer, flip_pos_y);
293 bool revert_y = true;
294 const uint_fast32_t next_error = check_distance_buff(data->distance_max, data->index, data->row_buffer, error);
295 if (next_error < error)
297 TRACE("Improved by flip-3 (%08X -> %08X)", error, next_error);
302 if (!((error = next_error) > 0U))
304 TRACE("success by flip-3 <<<---");
308 for (uint_fast16_t flip_pos_z = flip_pos_y + 1U; flip_pos_z < HASH_LEN; ++flip_pos_z)
310 flip_bit_at(data->row_buffer, flip_pos_z);
311 const uint_fast32_t next_error = check_distance_buff(data->distance_max, data->index, data->row_buffer, error);
312 if (next_error < error)
314 TRACE("Improved by flip-4 (%08X -> %08X)", error, next_error);
319 if (!((error = next_error) > 0U))
321 TRACE("success by flip-4 <<<---");
327 flip_bit_at(data->row_buffer, flip_pos_z);
332 flip_bit_at(data->row_buffer, flip_pos_y);
337 flip_bit_at(data->row_buffer, flip_pos_x);
342 flip_bit_at(data->row_buffer, flip_pos_w);
346 for (uint_fast16_t rand_mode = 0; rand_mode < 15U; ++rand_mode)
348 memcpy(temp, &data->row_buffer, sizeof(uint8_t) * ROW_LEN);
349 for (uint_fast16_t rand_loop = 0; rand_loop < 29927U; ++rand_loop)
353 case 0x0: msws_bytes(rand, &temp[0U * (ROW_LEN / 1U)], ROW_LEN / 1U); break;
354 case 0x1: msws_bytes(rand, &temp[0U * (ROW_LEN / 2U)], ROW_LEN / 2U); break;
355 case 0x2: msws_bytes(rand, &temp[1U * (ROW_LEN / 2U)], ROW_LEN / 2U); break;
356 case 0x3: msws_bytes(rand, &temp[0U * (ROW_LEN / 4U)], ROW_LEN / 4U); break;
357 case 0x4: msws_bytes(rand, &temp[1U * (ROW_LEN / 4U)], ROW_LEN / 4U); break;
358 case 0x5: msws_bytes(rand, &temp[2U * (ROW_LEN / 4U)], ROW_LEN / 4U); break;
359 case 0x6: msws_bytes(rand, &temp[3U * (ROW_LEN / 4U)], ROW_LEN / 4U); break;
360 case 0x7: msws_bytes(rand, &temp[0U * (ROW_LEN / 8U)], ROW_LEN / 8U); break;
361 case 0x8: msws_bytes(rand, &temp[1U * (ROW_LEN / 8U)], ROW_LEN / 8U); break;
362 case 0x9: msws_bytes(rand, &temp[2U * (ROW_LEN / 8U)], ROW_LEN / 8U); break;
363 case 0xA: msws_bytes(rand, &temp[3U * (ROW_LEN / 8U)], ROW_LEN / 8U); break;
364 case 0xB: msws_bytes(rand, &temp[4U * (ROW_LEN / 8U)], ROW_LEN / 8U); break;
365 case 0xC: msws_bytes(rand, &temp[5U * (ROW_LEN / 8U)], ROW_LEN / 8U); break;
366 case 0xD: msws_bytes(rand, &temp[6U * (ROW_LEN / 8U)], ROW_LEN / 8U); break;
367 case 0xE: msws_bytes(rand, &temp[7U * (ROW_LEN / 8U)], ROW_LEN / 8U); break;
370 const uint_fast32_t next_error = check_distance_buff(data->distance_max, data->index, temp, error);
371 if (next_error < error)
373 TRACE("Improved by rand-replace [%u] (%08X -> %08X)", rand_mode, error, next_error);
375 memcpy(data->row_buffer, temp, sizeof(uint8_t) * ROW_LEN);
376 if (!((error = next_error) > 0U))
378 TRACE("Success by rand-replace <<<---");
384 const double sigma = SQRT2 * (1.0 + (((double)round) / 498.5));
385 for (uint_fast16_t refine_loop = 0; refine_loop < 9973U; ++refine_loop)
387 if (!(refine_loop & 0x3FF))
389 if (SEM_TRYWAIT(data->stop))
394 const uint32_t flip_count = gaussian_noise_next(rand, &bxmller, sigma, 5U, HASH_LEN);
395 for (size_t refine_step = 0; refine_step < 997U; ++refine_step)
397 memcpy(temp, data->row_buffer, sizeof(uint8_t) * ROW_LEN);
398 flip_rand_n(temp, rand, flip_count);
399 const uint_fast32_t next_error = check_distance_buff(data->distance_max, data->index, temp, error);
400 if (next_error < error)
402 TRACE("Improved by rand-flip [%u] (%08X -> %08X)", flip_count, error, next_error);
404 memcpy(data->row_buffer, temp, sizeof(uint8_t) * ROW_LEN);
405 if (!((error = next_error) > 0U))
407 TRACE("Success by rand-flip (%u) <<<---", flip_count);
415 data->distance_max = min(data->distance_max + 3U, HASH_LEN); /*bump max. distance*/
424 if (check_distance_buff(data->distance_max, data->index, data->row_buffer, HASH_LEN))
426 fprintf(stderr, "ERROR MISCOMPARE!\n");
430 MUTEX_LOCK(data->mutex);
431 if (SEM_TRYWAIT(data->stop))
433 MUTEX_UNLOCK(data->mutex);
437 SEM_POST(data->stop, THREAD_COUNT);
438 MUTEX_UNLOCK(data->mutex);
439 return data->row_buffer; /*success*/
442 static void* thread_spin(void *const param)
444 unsigned long delay = 1U;
445 sem_t *const stop = ((sem_t*)param);
448 if (SEM_TRYWAIT(stop))
456 printf("\b\b\b[%c]", SPINNER[g_spinpos]);
457 g_spinpos = (g_spinpos + 1) % 4;
466 //-----------------------------------------------------------------------------
468 //-----------------------------------------------------------------------------
470 static bool save_table_data(const wchar_t *const filename, const size_t rows_completed_in, const uint_fast32_t current_dist_max)
472 wchar_t filename_temp[_MAX_PATH];
473 swprintf_s(filename_temp, _MAX_PATH, L"%s~%X", filename, make_seed());
474 FILE *const file = _wfopen(filename_temp, L"wb");
478 const uint64_t magic_number = MAGIC_NUMBER;
479 const uint32_t hash_len = HASH_LEN, distance_min = DISTANCE_MIN, distance_max = current_dist_max, rows_completed = (uint32_t)rows_completed_in;
480 fwrite(&magic_number, sizeof(uint64_t), 1, file);
481 fwrite(&hash_len, sizeof(uint32_t), 1, file);
482 fwrite(&distance_min, sizeof(uint32_t), 1, file);
483 fwrite(&distance_max, sizeof(uint32_t), 1, file);
484 fwrite(&rows_completed, sizeof(uint32_t), 1, file);
485 for (uint32_t i = 0; i < rows_completed; ++i)
487 const uint32_t checksum = adler32(&g_table[i][0], ROW_LEN);
488 fwrite(&checksum, sizeof(uint32_t), 1, file);
489 fwrite(&g_table[i][0], sizeof(uint8_t), ROW_LEN, file);
493 printf("ERROR: Failed to write table data!\n");
499 for (size_t i = 0; i < 42; ++i)
501 if (_wremove(filename))
505 printf("ERROR: Failed to delete existing file!\n");
512 if (_wrename(filename_temp, filename))
514 printf("ERROR: Failed to rename temp file!\n");
520 _wremove(filename_temp);
526 printf("ERROR: Failed to open table file for writing!\n");
531 static bool load_table_data(const wchar_t *const filename, size_t *const rows_completed_out, uint_fast32_t *const dist_max_out)
533 FILE *const file = _wfopen(filename, L"rb");
537 uint64_t magic_number;
538 uint32_t hash_len, distance_min, distance_max, rows_completed;
539 fread(&magic_number, sizeof(uint64_t), 1, file);
540 fread(&hash_len, sizeof(uint32_t), 1, file);
541 fread(&distance_min, sizeof(uint32_t), 1, file);
542 fread(&distance_max, sizeof(uint32_t), 1, file);
543 fread(&rows_completed, sizeof(uint32_t), 1, file);
544 if (ferror(file) || feof(file))
546 printf("ERROR: Failed to read the table header!\n");
550 if (magic_number != MAGIC_NUMBER)
552 printf("ERROR: Table file format could not be recognized!\n");
556 if ((hash_len != HASH_LEN) || (distance_min != DISTANCE_MIN) || (distance_max > HASH_LEN) || (rows_completed > ROW_NUM))
558 printf("ERROR: Table properties are incompatibe with this instance!\n");
562 for (size_t i = 0; i < rows_completed; ++i)
564 uint32_t checksum_expected;
565 if ((fread(&checksum_expected, sizeof(uint32_t), 1, file) != 1) || (fread(&g_table[i][0], sizeof(uint8_t), ROW_LEN, file) != ROW_LEN))
567 printf("ERROR: Failed to read table data from file!\n");
571 if (adler32(&g_table[i][0], ROW_LEN) != checksum_expected)
573 printf("ERROR: Table checksum does *not* match table contents!\n");
577 for (size_t j = 0; j < i; j++)
579 if (!check_distance_rows(distance_max, i, j))
581 printf("ERROR: Table distance verification has failed!\n");
589 if (success && rows_completed_out)
591 *rows_completed_out = (size_t)rows_completed;
592 *dist_max_out = distance_max;
598 printf("ERROR: Failed to open table file for reading!\n");
603 //-----------------------------------------------------------------------------
605 //-----------------------------------------------------------------------------
607 int wmain(int argc, wchar_t *argv[])
609 pthread_t thread_id[THREAD_COUNT + 1];
610 thread_data_t thread_data[THREAD_COUNT];
612 pthread_mutex_t stop_mutex;
613 FILE *file_out = NULL;
614 size_t initial_row_index = 0;
615 uint_fast32_t distance_max = DISTANCE_MIN;
617 printf("MHash GenTableXOR [%s]\n\n", __DATE__);
618 printf("HashLen: %d, Distance Min: %d, Threads: %d, MSVC: %u\n\n", HASH_LEN, DISTANCE_MIN, THREAD_COUNT, _MSC_FULL_VER);
620 if ((HASH_LEN % (8 * sizeof(uint32_t))) != 0)
622 crit_exit("FATAL: Hash length must be a multiple of 32 bits!");
627 printf("Table file not specified!\n\n");
629 printf(" GenTables_XOR.exe <table_file>\n\n");
633 for (size_t i = 0; i < ROW_NUM; i++)
635 memset(&g_table[i][0], 0, sizeof(uint8_t) * ROW_LEN);
638 memset(&thread_id, 0, sizeof(pthread_t) * (THREAD_COUNT + 1));
639 memset(&thread_data, 0, sizeof(thread_data_t) * THREAD_COUNT);
640 for (size_t t = 0; t < THREAD_COUNT; t++)
642 memset(&g_thread_buffer[t][0], 0, sizeof(uint8_t) * ROW_LEN);
645 SEM_INIT(&stop_flag);
646 MUTEX_INIT(&stop_mutex);
648 if (_waccess(argv[1], 4) == 0)
650 printf("Loading existing table data and proceeding...\n");
651 if (!load_table_data(argv[1], &initial_row_index, &distance_max))
657 for (size_t i = initial_row_index; i < ROW_NUM; i++)
659 char time_string[64];
660 printf("\aRow %03u of %03u [%c]", (uint32_t)(i+1U), ROW_NUM, SPINNER[g_spinpos]);
661 g_spinpos = (g_spinpos + 1) % 4;
663 PTHREAD_CREATE(&thread_id[THREAD_COUNT], NULL, thread_spin, &stop_flag);
664 for (size_t t = 0; t < THREAD_COUNT; t++)
666 thread_data[t].index = i;
667 thread_data[t].row_buffer = &g_thread_buffer[t][0];
668 thread_data[t].stop = &stop_flag;
669 thread_data[t].mutex = &stop_mutex;
670 thread_data[t].distance_max = distance_max;
671 PTHREAD_CREATE(&thread_id[t], NULL, thread_main, &thread_data[t]);
672 PTHREAD_SET_PRIORITY(thread_id[t], -15);
675 for (size_t t = 0; t < THREAD_COUNT; t++)
677 void *return_value = NULL;
678 PTHREAD_JOIN(thread_id[t], &return_value);
681 memcpy(&g_table[i][0], thread_data[t].row_buffer, sizeof(uint8_t) * ROW_LEN);
682 distance_max = max(distance_max, thread_data[t].distance_max);
686 PTHREAD_JOIN(thread_id[THREAD_COUNT], NULL);
687 get_time_str(time_string, 64);
688 printf("\b\b\b[#] - %s\n", time_string);
690 if (!save_table_data(argv[1], i + 1U, distance_max))
692 return 1; /*failed to save current table data*/
696 printf("\n-----\n\n");
699 if (fopen_s(&file_out, "table_XOR." DISTANCE_STR ".txt", "w") == 0)
701 dump_table(file_out);
705 printf("\n-----\n\n");
707 for (size_t i = 0; i < ROW_NUM; i++)
709 for (size_t j = 0; j < ROW_NUM; j++)
715 if (!check_distance_rows(distance_max, i, j))
717 crit_exit("FATAL: Table verification has failed!");
722 SEM_DESTROY(&stop_flag);
723 MUTEX_DESTROY(&stop_mutex);
725 printf("COMPLETED.\n\n");
726 system("shutdown /s /t 180");