void initialize(std::vector<stringT> const & words) { this->words = words; isInitialized = true; // construct trie trie.clear(); trie.push_back(trie_node()); for(size_t i = 0; i < words.size(); ++i) { stringT const & word = words[i]; for(C & c: word) { trie_node & current = trie[nodeIndex]; std::unordered_map<C,int> & edges = current.edges; auto nextIt = edges.find(c); if(nextIt == edges.end()) { trie_node t; t.fail_index = 0; t.parent_index = nodeIndex; nodeIndex = trie.size(); trie.push_back(t); edges[c] = nodeIndex; } nodeIndex = edges[c]; } trie[nodeIndex].endOf.insert(i); } // construct fallback std::queue<int> Q; Q.push(0); while(!Q.empty()) { int cur = Q.front(); Q.pop(); for(std::pair<C, int> kvp : trie[cur].edges) { // unpack pair C a = kvp.first; int u = kvp.second; trie_node & U = trie[u]; // queue destination Q.push(u); // find next fail index int v = U.fail_index; if(v == 0) { std::unordered_map<C,int> & edges = trie[0].edges; if(edges.find(a) == edges.end()) U.fail_index = 0; else U.fail_index = edges[a]; } else { while(trie[v].edges.find(a) == trie[v].edges.end()) v = trie[v].fail_index; U.fail_index = trie[v].edges[a]; } std::set<int> & failEndings = trie[U.fail_index].endOf; U.endOf.insert(begin(failEndings), end(failEndings)); } } }
int main(int argc, char** argv) { void* input = fopen("cipher1.txt", "r"); void* words = fopen("words.txt", "r"); int c, n; char* cipher = malloc(1024 * 1024 * 100); char* p; char buf[1024] = ""; char best_passwd[10] = "failed"; int pass[4]; int i = 0; int cipher_length; int j; trie* t = trie_node(); trie* node; int wc; int record = 0; int sum; if(!input) error("could not open cipher file"); if(!words) error("could not open words file"); if(!t) error("could not create trie"); printf("reading in cipher\n"); while(!feof(input)) { p = buf; while((c = fgetc(input)) != ',' && c >= 0) { *(p++) = c; } *p = 0; sscanf(buf, "%d", &n); cipher[i++] = n; printf("got %d -> %d\n", n, i); } cipher_length = i; printf("reading in words\n"); while(1) { if(fgets(buf, 1024, words) == 0) break; p = buf; node = t; while(*p && *p != '\n') { if(!node->map[*p]) if(!(node->map[*p] = trie_node())) error("trie node allocation"); node = node->map[*p]; ++p; } node->entry = 1; } pass[0] = pass[1] = pass[2] = 'a'; pass[3] = 0; while(!pass[3]) { for(i = 0; i <= 3; i++) if(pass[i] > 'z') { pass[i] = 'a'; pass[i+1]++; } node = t; wc = 0; for(i = 0; i < cipher_length; i++) { if(node->map[cipher[i] ^ (pass[i % 3])] != 0 && isalnum(cipher[i] ^ (pass[i % 3]))) { node = node->map[cipher[i] ^ (pass[i % 3])]; *p++ = (cipher[i] ^ (pass[i % 3])); *p = 0; } else goto clear_up; if(node->entry && strlen(buf) > 3) { ++wc; printf("password %c%c%c; found word: %s\n", *pass, pass[1], pass[2], buf); clear_up: *buf = 0; p = buf; node = t; } } if(wc > record) { record = wc; sprintf(best_passwd, "%c%c%c", *pass, pass[1], pass[2]); } ++*pass; } printf("best password found was '%s', which yielded %d wordfinds.\n", best_passwd, record); printf("decrypted message:\n"); for(i = 0; i < cipher_length; i++) putchar(cipher[i] ^ best_passwd[i % 3]); printf("\n"); sum = 0; for(i = 0; i < cipher_length; i++) sum += cipher[i] ^ best_passwd[i % 3]; printf("ascii sum: %d\n", sum); return 0; }