Problem Analysis
The cipher here is a repeating-key XOR cipher - a byte-level form of the Vigenere cipher. Every plaintext byte is combined with one byte of a short, cyclically repeating key using the bitwise XOR operation. XOR has a property that makes the scheme both convenient and breakable: it is its own inverse. Because (p ^ k) ^ k == p, decryption is the very same operation as encryption - you reapply the key. That is exactly why 65 XOR 42 = 107 and 107 XOR 42 = 65.
The observation that makes the key recoverable without knowing it is the periodicity of a repeating key. With a key of length k, the byte at position j is always encrypted with key byte j mod k. So key position 0 only ever touches ciphertext bytes 0, k, 2k, ...; key position 1 touches 1, k+1, 2k+1, ...; and so on. If I partition the ciphertext into k interleaved sub-sequences (one per key position), each sub-sequence was encrypted with a single constant byte - that is, each is a one-byte XOR cipher. I can break each independently. Because the problem tells me the key is three lowercase letters, every position has only 26 candidate values. Instead of searching the combinatorial space of 26^k full keys, I solve k separate one-dimensional problems of 26 trials each. That is the difference between exponential and linear work. To pick the right candidate per slice I use frequency analysis: natural English is dominated by e, t, a, and n, so the candidate byte that produces the most of these is almost certainly correct. The overall complexity is O(26 * n) for n ciphertext bytes - negligible.
Solution Approach
Frequency-Scoring Slice Attack (Python and C, index 0)
Both files implement the same algorithm and differ only in language idiom. It proceeds in four steps.
Step 1 - Parse the ciphertext. The input is a comma-separated list of decimal ASCII codes. Python uses a list comprehension, [int(x) for x in ...split(",")]. C scans the buffer character by character, accumulating digit runs into integers and pushing them into a dynamically grown array. Both fetch the file through a shared get_text_file helper.
Step 2 - Build interleaved slices. Given key length k, slice i holds ciphertext bytes at positions i, i+k, i+2k, ... Python expresses this directly with extended slice notation: encrypted[i::key_length]. C uses a two-pass approach: a first j % key_length pass counts each slice's size, then it allocates each slice to its exact size and a second pass routes elements in. This avoids over-allocation and per-slice reallocation.
Step 3 - Score each candidate byte per slice. For each candidate byte from 97 ('a') to 122 ('z'), and each slice, I XOR every element with the candidate and count how many results appear in the supplied list of common letters (eEaAnNtT). The highest-scoring candidate becomes that slice's key byte. I deliberately chose a plain count against a short alphabet rather than a full chi-squared test: the ciphertext is long and the per-slice key space is tiny, so the common-letter count is more than discriminating enough, and far simpler to reason about.
Step 4 - Compute the answer. With the per-position key known, I XOR each ciphertext byte back to plaintext and sum all ASCII values. Python caches the decrypted slice strings while scoring and reuses them; C runs a final XOR pass over each slice. The Python version also prints the recovered plaintext under --show - a valuable sanity check, since the bare answer 129448 gives no confidence the decryption is real English.