/* Generate strings len long and print n strings that hash to 0 * Referenced: http://codereview.stackexchange.com/q/38474 */ static void generate(int size, int len, char *string, int i, int *n) { // Constrain characters between A and z // to allow all characters: (char c = 1; c > 0 && *n > 0; c++) for (unsigned char c = MINCHAR; c <= MAXCHAR && *n > 0; c++) { string[i] = c; if (i == len - 1) { if (!universal_hash((unsigned char*) string, size)) { printf("%s\n", string); if (!--*n) break; } } else generate(size, len, string, i + 1, n); } }
/* Determine the value that combined with string hashes to 0 */ static char hash_zero(int *coeffs, char *string, int size, int c) { gcd euclid = extended_euclid(size, coeffs[c]); // euclid.y + size to ensure it's positive euclid.y = (euclid.y + size) % size; // Get the hash of string excluding the char at c int hash = universal_hash((unsigned char*)string, size); hash -= coeffs[c] * (unsigned char) string[c] % size; // size is prime so euclid.y * coeffs % size = 1 // So hash + (size - hash) * 1 = size % size = 0 return (size - hash) * euclid.y % size; }
/* Print n strings that are hashed to 0 by universal_hash seeded with seed */ void collide_dumb(unsigned int size, unsigned int seed, int n) { char* zeroHashStrings[n]; int zeroHashCounter = 0 ; //While we don't have enough random numbers, keep trying strings while(zeroHashCounter < n) { char* string = randstring(); if(universal_hash((unsigned char*)string, size)==0) { zeroHashStrings[zeroHashCounter]= string; zeroHashCounter++; } } //The number of r values generated is always the maximum string length fprintf(stdout, "%d\n", MAXSTRLEN); //Reinitialize the random number generator to get the values we want srand(seed); //Print the r values int i; for(i = 0 ; i < MAXSTRLEN; i++) { fprintf( stdout, "%d\n" ,rand()%size); } for(i = 0 ; i < n; i++) { fprintf( stdout, "%s\n" ,zeroHashStrings[i]); } }
/* Print n strings that are hashed to 0 by universal_hash seeded with seed * although character can be anything <255, only 'pretty' characters are chosen * for the 'prettiness' of the output */ void collide_clever(unsigned int size, unsigned int seed, int n) { static bool first = true; int randSize, sum, gen, i, x, toChange, *randArr = NULL; unsigned char y, *line = malloc(sizeof(*line) * MAX_LEN); // index randsize will be '\0'. Therefore, randsize < MAXLEN. #if I_DUNNO_STATS unsigned char **used = malloc(sizeof(*used) * n); int useCount = 0; #endif if(size > 255) { fprintf(stderr, "Size is too big. Outside assignment scope!\n"); fprintf(stderr, "I had spent ages addressing that but after nerf,\n"); fprintf(stderr, "and reached the state where generated string hash to one index for any size.\n"); fprintf(stderr, "But no point working further on and submitting risky long code.\n"); fprintf(stderr, "Anyway, terminating in sass :P\n"); exit(EXIT_FAILURE); } // initialize universal hash's random array if(first == true) { // some say there are still first == true for most CompSc students first = false; srand(seed); universal_hash(line, size); } // find out which index to work on randArr = getRandArray(seed, size); i = 0; while(randArr[i] == 0) i++; toChange = i; #if GET_TIME clock_t start = clock(); fprintf(stderr, "N: %d\nSIZE: %d\n", n, size); #endif // initialize my random array while(n > 0) { sum = 0; randSize = rand() % (MAX_LEN - INIT_SIZE - 1) + INIT_SIZE; line[randSize] = '\0'; for(i = 0; i < randSize; i++) { if(i != toChange) { line[i] = rand() % (MAX_ASCII - START_ASCII - 1) + START_ASCII; sum += (line[i] * randArr[i]); } } // explanation of how and why this works and the algorithm is in the report, question 7. gen = size - (sum % size); tuple_t t = extEuclid(size, randArr[toChange]); x = t.b * gen / t.c; if(x < 0) y = size - ((-x) % size); else y = x % size; if(y < START_ASCII && size + y < MAX_ASCII) { y += size * (1 + (START_ASCII - y) / size); // minimum multiple of size to add to make y fall within given range } else if(y == '\n' || y == 127 || y <= 32) { // 127 = DEL ASCII // if the string genrated has newline character, solution is not valid since // strings are loaded with fgets(). // this happens is about 0.3% of the time. // Forum post requirement: avoid characters from 0-32. continue; // had attempted to add minimum multiple of size, // faster to generate new rather than resolve } line[toChange] = y; #if I_DUNNO_STATS for(i = 0; i < useCount; i++) { // make sure it is not duplicate if(strcmp((char*) used[i], (char*) line) == 0) break; } used[useCount] = malloc(sizeof(unsigned char) * (strlen((char*)line) + 1)); strcpy((char*)used[useCount], (char*)line); // fprintf(stderr, "USED %d: %s\n", useCount, used[useCount]); useCount++; #endif fprintf(stdout, "%s\n", line); n--; } #if GET_TIME clock_t end = clock(); fprintf(stderr, "TIME TAKEN: %.5f s\n", ((double) end - start) / CLOCKS_PER_SEC); #endif #if I_DUNNO_STATS for(i = 0; i < useCount; i++) { free(used[i]); } free(used); #endif free(randArr); free(line); }
/* Print n strings that are hashed to 0 by universal_hash seeded with seed * although character can be anything <255, only 'pretty' characters are chosen * for the 'prettiness' of the output */ void collide_dumb(unsigned int size, unsigned int seed, int n) { static bool first = true; int *randArr = getRandArray(seed, size); unsigned int randSize, i, try; unsigned char *line = malloc(sizeof(*line) * MAX_LEN); #if I_DUNNO_STATS unsigned char **used = malloc(sizeof(*used) * n); unsigned int useCount = 0; // index randsize will be '\0'. Therefore, randsize < MAXLEN. #endif if(first == true) { // if virgin, initialize universal hash first = false; srand(seed); universal_hash(line, size); } #if GET_TIME clock_t start = clock(); fprintf(stderr, "N: %d\nSIZE: %d\n", n, size); #endif while(n > 0) { try = 0; randSize = rand() % (MAX_LEN - INIT_SIZE - 1) + INIT_SIZE; // -1 for \0 slot while(try <= MAX_TRY) { for(i = 0; i < randSize; i++) line[i] = rand() % (MAX_ASCII - START_ASCII - 1) + START_ASCII; line[randSize] = '\0'; if(universal_hash(line, size) == 0) { #if I_DUNNO_STATS for(i = 0; i < useCount; i++) { // make sure it is not duplicate if(strcmp((char*) used[i], (char*) line) == 0) break; } used[useCount] = malloc(sizeof(unsigned char) * (strlen((char*)line) + 1)); strcpy((char*)used[useCount], (char*)line); // fprintf(stderr, "USED %d: %s\n", useCount, used[useCount]); useCount++; #endif fprintf(stdout, "%s\n", line); n--; break; // now generate new random size! } } } #if GET_TIME clock_t end = clock(); fprintf(stderr, "TIME TAKEN: %.5f s\n", ((double) end - start) / CLOCKS_PER_SEC); #endif #if I_DUNNO_STATS for(i = 0; i < useCount; i++) { free(used[i]); } free(used); #endif free(randArr); free(line); }