tuple_t extEuclid(unsigned int a, unsigned int b) { if(a < b) { // a must be the greater one unsigned int t = a; a = b; b = t; } if(b == 0) return (tuple_t){1, 0, a}; tuple_t t = extEuclid(b, a % b); return (tuple_t){t.b, t.a - (a/b) * t.b, t.c}; }
/* 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); }
int modInv(int n, int m) { int x, y, gcd; extEuclid(n, m, x, y, gcd); if (gcd == 1) return x % m; return 0; }