The ciphertext is given as a comma-separated list of ASCII codes obtained by XOR-encrypting an English plaintext with a repeating key of length 3. Each key character is a lowercase English letter, so the key belongs to a set with only \(26^3\) possibilities. The task is to recover the intended plaintext and then compute the sum of its ASCII values.
The decisive facts are that XOR is its own inverse, the key repeats every three positions, and the implementations do not use a separate cryptanalytic shortcut. They test every admissible key and rank the resulting plaintexts with an explicit English-text score.
Let the ciphertext be \(e_0,e_1,\dots,e_{n-1}\). For a candidate key \(k=(k_0,k_1,k_2)\) with each \(k_r\in\{97,98,\dots,122\}\), the decrypted byte at position \(i\) is
$$p_i(k)=e_i \oplus k_{i \bmod 3}.$$
This turns the problem into a finite optimization problem over the key set \(K=\{97,\dots,122\}^3\).
The basic invariant is
$$x \oplus y \oplus y = x.$$
If a plaintext byte \(p_i\) was encrypted as \(e_i=p_i \oplus k_{i \bmod 3}\), then applying the same key byte again restores the original symbol:
$$e_i \oplus k_{i \bmod 3}=(p_i \oplus k_{i \bmod 3}) \oplus k_{i \bmod 3}=p_i.$$
No recurrence is needed. Once the key is fixed, every plaintext byte is determined independently by this identity, and the period 3 tells us exactly which key byte is used at each index.
Because the key has length 3 and each character must be a lowercase ASCII letter,
$$|K|=26^3=17{,}576.$$
That is small enough for direct exhaustive search. For each key, decryption costs one XOR per ciphertext position, so the entire search is completely practical. This is why the solution does not need a more elaborate derivation from residue classes or classical frequency tables.
The method is exact relative to its scoring rule: it does not estimate the best key, it evaluates every candidate key and keeps the best-scoring plaintext.
The implementations use a hard validity filter followed by a weighted English-text score. If any decrypted character lies outside the ASCII interval from 9 through 126, the candidate is rejected by assigning a very large negative score. Otherwise the score is
$$S(p)=3N_{\text{space}}(p)+2N_{\text{letter}}(p)+40W_{\text{the}}(p)+25W_{\text{and}}(p)+20W_{\text{of}}(p)+20W_{\text{to}}(p),$$
where \(N_{\text{space}}\) counts spaces, \(N_{\text{letter}}\) counts uppercase and lowercase English letters, and \(W_{\text{word}}\) counts occurrences of the indicated word written with surrounding spaces.
So the selected key is
$$k^\star=\operatorname*{arg\,max}_{k\in K} S(p(k)).$$
This is the real mathematical object used by the code. The search is performed on fully decrypted texts, not by solving each key position separately.
The implementations include a small checkpoint with the plaintext “hello world” and the key “abc”. Writing the key bytes as \(97,98,99\), the first encrypted values are
$$104\oplus97=9,\qquad 101\oplus98=7,\qquad 108\oplus99=15,$$
and continuing with the same period-3 pattern gives the ciphertext prefix \([9,7,15,13,13,67,\dots]\). Decrypting with the same repeating key reverses the process:
$$9\oplus97=104,\qquad 7\oplus98=101,\qquad 15\oplus99=108.$$
The original text is recovered exactly. A wrong key may still produce printable symbols, but it usually scores much worse because it contains fewer letters, fewer spaces, and few or no common English words.
Once the maximizing plaintext \(p(k^\star)\) has been found, the required result is simply
$$A=\sum_{i=0}^{n-1} p_i(k^\star).$$
The search phase identifies the plaintext, and the final summation converts that plaintext into the requested integer.
The C++, Python, and Java implementations read the ciphertext as raw text and scan it character by character. Consecutive decimal digits are collected into one token, converted to an integer, and appended to the ciphertext array. Commas and line breaks act only as separators.
Next, the implementation loops through all triples of lowercase letters. For each triple, it decrypts the entire ciphertext with the repeating period-3 XOR rule and materializes the candidate plaintext as a string.
Each candidate plaintext is checked against the ASCII-range filter and then scored with the weighted English-text formula. Whenever a candidate beats the best score seen so far, the implementation stores it as the current winner. After the full \(26^3\) search finishes, it sums the ASCII codes of the winning plaintext. Before the main search, the implementations also verify the XOR round-trip identity on a short known example.
If \(n\) is the number of ciphertext bytes, parsing costs \(O(n)\). The exhaustive search tries \(26^3\) keys, and each key requires \(O(n)\) work to decrypt and score the text, so the dominant running time is
$$O(26^3 n).$$
Because \(26^3=17{,}576\) is a fixed constant, the runtime is linear in the message length with a moderate constant factor. The extra word-count passes in the score are over four fixed short words, so they do not change the asymptotic bound.
The memory usage is \(O(n)\): the implementations store the ciphertext, one current plaintext, and a constant amount of bookkeeping for the best score and the key enumeration.
Der Chiffretext ist als kommagetrennte Liste von ASCII-Zahlen gegeben. Er entstand aus einem englischen Klartext durch XOR-Verschlüsselung mit einem periodischen Schlüssel der Länge 3. Jeder Schlüsselbuchstabe ist ein englischer Kleinbuchstabe, also liegt der Schlüssel in einer Menge mit nur \(26^3\) Möglichkeiten. Gesucht sind der richtige Klartext und danach die Summe seiner ASCII-Werte.
Entscheidend sind drei Punkte: XOR ist seine eigene Umkehrung, der Schlüssel wiederholt sich alle drei Positionen, und die Implementierungen verwenden keinen separaten Krypto-Trick. Stattdessen prüfen sie jeden zulässigen Schlüssel und bewerten den entstehenden Text mit einer expliziten Englisch-Heuristik.
Bezeichne den Chiffretext mit \(e_0,e_1,\dots,e_{n-1}\). Für einen Kandidatenschlüssel \(k=(k_0,k_1,k_2)\) mit \(k_r\in\{97,98,\dots,122\}\) lautet das entschlüsselte Byte an Position \(i\)
$$p_i(k)=e_i \oplus k_{i \bmod 3}.$$
Damit wird das gesamte Problem zu einer endlichen Optimierungsaufgabe über der Schlüsselmengen \(K=\{97,\dots,122\}^3\).
Die zentrale Invariante ist
$$x \oplus y \oplus y = x.$$
Wenn ein Klartextbyte \(p_i\) als \(e_i=p_i \oplus k_{i \bmod 3}\) verschlüsselt wurde, dann stellt dieselbe Schlüsselkomponente den Originalwert wieder her:
$$e_i \oplus k_{i \bmod 3}=(p_i \oplus k_{i \bmod 3}) \oplus k_{i \bmod 3}=p_i.$$
Eine Rekurrenz ist hier nicht nötig. Sobald der Schlüssel feststeht, ist jedes Zeichen unabhängig bestimmt, und die Periodenlänge 3 legt exakt fest, welches Schlüsselbyte zu welchem Index gehört.
Da der Schlüssel Länge 3 hat und jeder Buchstabe ein Kleinbuchstabe im ASCII-Bereich ist, gilt
$$|K|=26^3=17{,}576.$$
Diese Zahl ist klein genug für eine direkte vollständige Suche. Für jeden Schlüssel kostet die Entschlüsselung nur ein XOR pro Position, also bleibt die gesamte Suche problemlos beherrschbar. Genau deshalb braucht die Lösung weder eine feinere Aufspaltung nach Restklassen noch klassische Häufigkeitstabellen.
Die Methode ist relativ zu ihrer Bewertungsfunktion exakt: Es wird kein Schlüssel geschätzt, sondern jeder mögliche Schlüssel geprüft und der beste Text ausgewählt.
Die Implementierungen kombinieren einen harten Gültigkeitsfilter mit einer gewichteten Englisch-Bewertung. Falls irgendein entschlüsseltes Zeichen außerhalb des ASCII-Intervalls von 9 bis 126 liegt, wird der Kandidat durch einen sehr großen negativen Wert verworfen. Andernfalls lautet die Punktzahl
$$S(p)=3N_{\text{space}}(p)+2N_{\text{letter}}(p)+40W_{\text{the}}(p)+25W_{\text{and}}(p)+20W_{\text{of}}(p)+20W_{\text{to}}(p),$$
wobei \(N_{\text{space}}\) die Leerzeichen zählt, \(N_{\text{letter}}\) Groß- und Kleinbuchstaben zählt und \(W_{\text{word}}\) die Vorkommen des jeweiligen Wortes mitsamt umgebenden Leerzeichen zählt.
Der ausgewählte Schlüssel ist also
$$k^\star=\operatorname*{arg\,max}_{k\in K} S(p(k)).$$
Genau dieses Optimierungsproblem wird tatsächlich gelöst. Die Implementierungen rekonstruieren die drei Schlüsselpositionen nicht getrennt, sondern bewerten immer den vollständig entschlüsselten Text.
In den Implementierungen gibt es einen kleinen Test mit dem Klartext „hello world“ und dem Schlüssel „abc“. Schreibt man die Schlüsselbytes als \(97,98,99\), dann entstehen am Anfang die Werte
$$104\oplus97=9,\qquad 101\oplus98=7,\qquad 108\oplus99=15,$$
und beim Weiterlaufen mit derselben Periode 3 erhält man den Chiffretext-Präfix \([9,7,15,13,13,67,\dots]\). Entschlüsselt man mit demselben periodischen Schlüssel, kehrt sich der Prozess um:
$$9\oplus97=104,\qquad 7\oplus98=101,\qquad 15\oplus99=108.$$
Der ursprüngliche Text erscheint exakt wieder. Ein falscher Schlüssel kann zwar druckbare Zeichen erzeugen, verliert aber meistens deutlich bei der Bewertung, weil er weniger Buchstaben, weniger Leerzeichen und kaum häufige englische Wörter enthält.
Sobald der beste Klartext \(p(k^\star)\) gefunden ist, lautet die gesuchte Größe einfach
$$A=\sum_{i=0}^{n-1} p_i(k^\star).$$
Die Suche bestimmt den Klartext, und die abschließende Summe übersetzt ihn in die verlangte ganze Zahl.
Die C++-, Python- und Java-Implementierungen lesen den Chiffretext als rohen Text und laufen Zeichen für Zeichen darüber. Aufeinanderfolgende Dezimalziffern werden zu einem Token gesammelt, in eine Zahl umgewandelt und an das Chiffretext-Array angehängt. Kommata und Zeilenumbrüche dienen nur als Trenner.
Danach durchläuft die Implementierung alle Tripel aus Kleinbuchstaben. Für jedes Tripel wird der gesamte Chiffretext mit der periodischen XOR-Regel der Länge 3 entschlüsselt und als Kandidatenstring aufgebaut.
Jeder Kandidat wird zuerst durch den ASCII-Filter geprüft und anschließend mit der gewichteten Englisch-Funktion bewertet. Immer wenn ein Kandidat besser abschneidet als alle zuvor getesteten Schlüssel, wird er als aktueller Sieger gespeichert. Nach Abschluss der vollständigen \(26^3\)-Suche werden die ASCII-Werte dieses Siegertexts aufsummiert. Vor der Hauptsuche prüfen die Implementierungen außerdem an einem kurzen Beispiel die XOR-Rundweg-Eigenschaft.
Ist \(n\) die Anzahl der Chiffretext-Bytes, dann kostet das Parsen \(O(n)\). Die vollständige Suche testet \(26^3\) Schlüssel, und jeder Schlüssel benötigt \(O(n)\) Arbeit für Entschlüsselung und Bewertung. Die dominante Laufzeit ist also
$$O(26^3 n).$$
Da \(26^3=17{,}576\) eine feste Konstante ist, bleibt die Laufzeit linear in der Nachrichtenlänge, nur mit einem moderaten konstanten Faktor. Die zusätzlichen Wortzählungen betreffen vier feste kurze Wörter und ändern deshalb die asymptotische Schranke nicht.
Der Speicherverbrauch ist \(O(n)\): gespeichert werden der Chiffretext, jeweils ein aktueller Klartext und eine konstante Menge an Verwaltungsdaten für den bisher besten Wert und die Schlüsselschleifen.
Şifreli metin, İngilizce bir düz metnin uzunluğu 3 olan tekrarlı bir anahtarla XOR uygulanması sonucu oluşmuş ASCII kodlarının virgülle ayrılmış listesidir. Anahtarın her karakteri küçük İngilizce harftir; dolayısıyla anahtar uzayı yalnızca \(26^3\) olasılık içerir. Amaç doğru düz metni bulmak ve sonra onun ASCII değerleri toplamını hesaplamaktır.
Belirleyici üç nokta şunlardır: XOR kendi tersidir, anahtar her üç konumda bir tekrar eder ve uygulamalar ayrı bir kriptanaliz kestirimi kullanmaz. Bunun yerine tüm geçerli anahtarları deneyip ortaya çıkan metinleri açık bir İngilizce-benzerlik puanıyla sıralarlar.
Şifreli metni \(e_0,e_1,\dots,e_{n-1}\) ile gösterelim. Her \(k_r\in\{97,98,\dots,122\}\) olmak üzere aday anahtar \(k=(k_0,k_1,k_2)\) için \(i\). konumdaki çözülmüş bayt
$$p_i(k)=e_i \oplus k_{i \bmod 3}$$
olur. Böylece problem, \(K=\{97,\dots,122\}^3\) kümesi üzerinde sonlu bir optimizasyon problemine dönüşür.
Temel değişmez
$$x \oplus y \oplus y = x$$
eşitliğidir. Eğer bir düz metin baytı \(p_i\), \(e_i=p_i \oplus k_{i \bmod 3}\) biçiminde şifrelenmişse aynı anahtar baytını yeniden uygulamak orijinal karakteri geri getirir:
$$e_i \oplus k_{i \bmod 3}=(p_i \oplus k_{i \bmod 3}) \oplus k_{i \bmod 3}=p_i.$$
Burada bir yineleme bağıntısına gerek yoktur. Anahtar sabitlendiği anda her konum bağımsız olarak belirlenir ve periyot 3 kuralı hangi indekste hangi anahtar baytının kullanılacağını tamamen açık hale getirir.
Anahtar uzunluğu 3 ve her karakter küçük ASCII harfi olduğu için
$$|K|=26^3=17{,}576.$$
Bu büyüklük tam tarama için yeterince küçüktür. Her anahtar için gereken işlem, şifreli metindeki her konumda tek bir XOR yapmaktır. Bu nedenle çözümün artık sınıflarına ayrılmış daha karmaşık bir frekans analizi kurmasına gerek kalmaz.
Yöntem, kullandığı puanlama ölçütüne göre eksiksizdir: en iyi anahtar tahmin edilmez, bütün adaylar değerlendirilir ve en yüksek puanlı düz metin seçilir.
Uygulamalar önce sert bir geçerlilik filtresi, sonra ağırlıklı bir İngilizce metin puanı kullanır. Eğer çözülmüş karakterlerden herhangi biri 9 ile 126 arasındaki ASCII aralığının dışına düşerse aday çok büyük negatif bir puanla elenir. Aksi durumda puan
$$S(p)=3N_{\text{space}}(p)+2N_{\text{letter}}(p)+40W_{\text{the}}(p)+25W_{\text{and}}(p)+20W_{\text{of}}(p)+20W_{\text{to}}(p)$$
şeklindedir. Burada \(N_{\text{space}}\) boşluk sayısını, \(N_{\text{letter}}\) büyük ve küçük İngilizce harflerin sayısını, \(W_{\text{word}}\) ise ilgili sözcüğün iki yanında boşluk olacak biçimde kaç kez geçtiğini sayar.
Dolayısıyla seçilen anahtar
$$k^\star=\operatorname*{arg\,max}_{k\in K} S(p(k))$$
olur. Kodun çözdüğü gerçek matematiksel nesne budur. Yani anahtarın üç konumu ayrı ayrı çözülmez; her zaman tüm metin çözülüp puanlanır.
Uygulamalardaki küçük doğrulama örneği “hello world” düz metni ve “abc” anahtarıdır. Anahtar baytlarını \(97,98,99\) olarak yazarsak ilk şifreli değerler
$$104\oplus97=9,\qquad 101\oplus98=7,\qquad 108\oplus99=15$$
olur; aynı periyot 3 düzeni sürdürülünce şifreli önek \([9,7,15,13,13,67,\dots]\) elde edilir. Aynı tekrarlı anahtarla tekrar XOR yapılınca süreç tersine döner:
$$9\oplus97=104,\qquad 7\oplus98=101,\qquad 15\oplus99=108.$$
Böylece orijinal metin eksiksiz geri gelir. Yanlış bir anahtar bazen yazdırılabilir karakterler üretebilir; fakat genellikle daha az harf, daha az boşluk ve daha az yaygın İngilizce sözcük içerdiği için puanı belirgin biçimde düşer.
En yüksek puanlı düz metin \(p(k^\star)\) bulunduğunda sorunun istediği değer yalnızca
$$A=\sum_{i=0}^{n-1} p_i(k^\star)$$
toplamıdır. Arama aşaması metni belirler, son toplam ise bu metni istenen tam sayıya çevirir.
C++, Python ve Java uygulamaları girdi metnini ham karakter dizisi olarak okur ve karakter karakter tarar. Art arda gelen ondalık rakamlar tek bir token içinde toplanır, sayıya çevrilir ve şifreli metin dizisine eklenir. Virgüller ile satır sonları yalnızca ayırıcıdır.
Sonraki aşamada küçük harflerden oluşan tüm üçlüler dolaşılır. Her üçlü için tüm şifreli metin, periyodu 3 olan tekrarlı XOR kuralıyla çözülür ve aday düz metin bir karakter dizisi olarak oluşturulur.
Her aday düz metin önce ASCII aralık filtresinden geçirilir, sonra ağırlıklı İngilizce puanıyla değerlendirilir. Bir aday o ana kadar görülen en iyi skoru geçtiğinde yeni en iyi metin olarak saklanır. Tüm \(26^3\) arama bittiğinde kazanan metnin ASCII kodları toplanır. Ana arama başlamadan önce uygulamalar kısa bir örnek üzerinde XOR'un gidiş-dönüş özelliğini de kontrol eder.
\(n\) şifreli metin bayt sayısı olsun. Ayrıştırma \(O(n)\) zaman alır. Kapsamlı arama \(26^3\) anahtar dener ve her anahtar için çözme ile puanlama \(O(n)\) iş gerektirir. Baskın çalışma süresi bu yüzden
$$O(26^3 n)$$
olur. \(26^3=17{,}576\) sabit bir sayı olduğundan çalışma süresi mesaj uzunluğunda doğrusaldır; yalnızca sabit katsayısı orta büyüklüktedir. Puanlama sırasında yapılan ek kelime sayımları dört sabit kısa ifade üzerinde çalıştığı için asimptotik sınırı değiştirmez.
Bellek kullanımı \(O(n)\)'dir. Bunun nedeni şifreli metnin, o anda üretilen bir düz metnin ve en iyi skora ilişkin sabit boyutlu birkaç değişkenin tutulmasıdır.
El texto cifrado aparece como una lista de códigos ASCII separados por comas. Proviene de un texto en inglés cifrado con XOR usando una clave repetida de longitud 3. Cada carácter de la clave es una letra minúscula inglesa, así que el espacio de claves contiene solo \(26^3\) posibilidades. La tarea consiste en recuperar el texto correcto y después sumar sus valores ASCII.
Los hechos decisivos son tres: XOR es su propio inverso, la clave se repite cada tres posiciones y las implementaciones no usan un atajo criptanalítico independiente. En cambio, prueban todas las claves admisibles y ordenan los textos obtenidos mediante una puntuación explícita de apariencia inglesa.
Sea el texto cifrado \(e_0,e_1,\dots,e_{n-1}\). Para una clave candidata \(k=(k_0,k_1,k_2)\) con \(k_r\in\{97,98,\dots,122\}\), el byte descifrado en la posición \(i\) es
$$p_i(k)=e_i \oplus k_{i \bmod 3}.$$
Esto convierte todo el problema en una optimización finita sobre el conjunto \(K=\{97,\dots,122\}^3\).
La identidad fundamental es
$$x \oplus y \oplus y = x.$$
Si un byte del texto plano \(p_i\) fue cifrado como \(e_i=p_i \oplus k_{i \bmod 3}\), entonces aplicar de nuevo el mismo byte de clave restaura el símbolo original:
$$e_i \oplus k_{i \bmod 3}=(p_i \oplus k_{i \bmod 3}) \oplus k_{i \bmod 3}=p_i.$$
Aquí no hace falta ninguna recurrencia. Una vez fijada la clave, cada posición queda determinada de manera independiente, y el período 3 indica exactamente qué componente de la clave actúa sobre cada índice.
Como la clave tiene longitud 3 y cada carácter debe ser una letra minúscula ASCII, se cumple
$$|K|=26^3=17{,}576.$$
Esa cantidad es lo bastante pequeña para una búsqueda exhaustiva directa. Para cada clave, descifrar cuesta un XOR por posición del texto cifrado, así que el recorrido completo es perfectamente viable. Por eso la solución no necesita una derivación más complicada por clases de residuos ni tablas clásicas de frecuencias.
El método es exacto con respecto a su criterio de puntuación: no estima la mejor clave, sino que evalúa todas y conserva el texto con la puntuación máxima.
Las implementaciones usan primero un filtro duro de validez y luego una puntuación ponderada de texto inglés. Si algún carácter descifrado cae fuera del intervalo ASCII de 9 a 126, el candidato se descarta con una puntuación muy negativa. En caso contrario, la puntuación es
$$S(p)=3N_{\text{space}}(p)+2N_{\text{letter}}(p)+40W_{\text{the}}(p)+25W_{\text{and}}(p)+20W_{\text{of}}(p)+20W_{\text{to}}(p).$$
Aquí \(N_{\text{space}}\) cuenta espacios, \(N_{\text{letter}}\) cuenta letras inglesas mayúsculas y minúsculas, y \(W_{\text{word}}\) cuenta las apariciones de la palabra indicada escritas con espacios a ambos lados.
Por lo tanto, la clave elegida es
$$k^\star=\operatorname*{arg\,max}_{k\in K} S(p(k)).$$
Este es el objeto matemático real que utiliza el código. No se resuelven por separado las tres posiciones de la clave; siempre se evalúa el texto ya descifrado en su totalidad.
Las implementaciones incluyen una comprobación pequeña con el texto plano “hello world” y la clave “abc”. Si escribimos los bytes de la clave como \(97,98,99\), los primeros valores cifrados son
$$104\oplus97=9,\qquad 101\oplus98=7,\qquad 108\oplus99=15,$$
y al continuar con el mismo patrón de período 3 se obtiene el prefijo cifrado \([9,7,15,13,13,67,\dots]\). Al descifrar con la misma clave repetida, el proceso se invierte:
$$9\oplus97=104,\qquad 7\oplus98=101,\qquad 15\oplus99=108.$$
El texto original se recupera exactamente. Una clave incorrecta puede producir símbolos imprimibles, pero normalmente obtiene una puntuación mucho menor porque contiene menos letras, menos espacios y pocas o ninguna palabra inglesa frecuente.
Una vez hallado el texto ganador \(p(k^\star)\), la respuesta pedida por el problema es simplemente
$$A=\sum_{i=0}^{n-1} p_i(k^\star).$$
La búsqueda identifica el texto correcto y la suma final lo transforma en el entero solicitado.
Las implementaciones en C++, Python y Java leen el contenido como texto bruto y lo recorren carácter por carácter. Los dígitos decimales consecutivos se agrupan en un mismo token, se convierten en entero y se añaden al arreglo del texto cifrado. Las comas y los saltos de línea actúan solo como separadores.
Después, la implementación recorre todos los ternas posibles de letras minúsculas. Para cada terna descifra el mensaje completo con la regla XOR periódica de longitud 3 y construye el texto plano candidato como una cadena.
Cada texto candidato pasa primero por el filtro del rango ASCII y luego por la puntuación ponderada de inglés. Cuando un candidato supera la mejor puntuación observada hasta ese momento, pasa a ser el mejor texto actual. Tras completar la búsqueda \(26^3\), se suman los códigos ASCII del texto ganador. Antes de la búsqueda principal, las implementaciones también verifican la identidad de ida y vuelta de XOR con un ejemplo breve conocido.
Si \(n\) es el número de bytes del texto cifrado, el análisis inicial cuesta \(O(n)\). La búsqueda exhaustiva prueba \(26^3\) claves, y cada clave requiere \(O(n)\) trabajo para descifrar y puntuar. Por tanto, el coste dominante es
$$O(26^3 n).$$
Como \(26^3=17{,}576\) es una constante fija, el tiempo es lineal en la longitud del mensaje con un factor constante moderado. Las búsquedas adicionales de palabras solo recorren cuatro patrones cortos fijos, de modo que no alteran la cota asintótica.
El uso de memoria es \(O(n)\), porque la implementación mantiene el texto cifrado, un texto plano actual y una cantidad constante de información auxiliar para la mejor puntuación y la enumeración de claves.
题目给出的是一串用逗号分隔的 ASCII 整数,它们来自一段英文原文在长度为 3 的循环密钥下经过 XOR 加密后的结果。密钥的每个字符都限制为英文小写字母,因此全部可能的密钥只有 \(26^3\) 个。目标是恢复正确的英文文本,然后计算该文本全部 ASCII 值的总和。
真正决定解法的事实有三个:XOR 运算是自反可逆的,密钥每隔 3 个位置重复一次,而且这些实现并没有使用单独的密码分析捷径。它们采取的是完全枚举所有合法密钥,再用一个明确写出的英文文本评分函数对解密结果进行比较。
设密文为 \(e_0,e_1,\dots,e_{n-1}\)。对于候选密钥 \(k=(k_0,k_1,k_2)\),其中每个 \(k_r\in\{97,98,\dots,122\}\),位置 \(i\) 上的解密字节为
$$p_i(k)=e_i \oplus k_{i \bmod 3}.$$
这样一来,整个问题就被改写成密钥集合 \(K=\{97,\dots,122\}^3\) 上的一个有限优化问题。
核心不变量是
$$x \oplus y \oplus y = x.$$
如果某个明文字节 \(p_i\) 在加密时变成了 \(e_i=p_i \oplus k_{i \bmod 3}\),那么再次对它异或同一个密钥字节,就会回到原来的字符:
$$e_i \oplus k_{i \bmod 3}=(p_i \oplus k_{i \bmod 3}) \oplus k_{i \bmod 3}=p_i.$$
这里不需要任何递推关系。一旦密钥固定下来,每个位置的明文字节都由这个恒等式单独决定,而周期 3 则准确告诉我们每个位置应当使用哪一个密钥字节。
因为密钥长度是 3,且每个字符必须是小写 ASCII 字母,所以
$$|K|=26^3=17{,}576.$$
这个数量足够小,可以直接进行穷举。对每一个候选密钥,解密只需要对每个密文字节做一次 XOR,因此整体搜索在计算上完全可行。这也是为什么解法不必额外构造按模 3 分类的频率分析推导。
从评分准则的角度看,这个方法是精确的:实现并不是“猜测”哪个密钥最好,而是把所有候选都试一遍,再选择评分最高的那一个。
实现先做一个硬性的有效性过滤,再计算一个带权英文评分。如果某个解密字符落在 ASCII 9 到 126 之外,就给这个候选一个非常大的负分,直接将其淘汰。否则评分定义为
$$S(p)=3N_{\text{space}}(p)+2N_{\text{letter}}(p)+40W_{\text{the}}(p)+25W_{\text{and}}(p)+20W_{\text{of}}(p)+20W_{\text{to}}(p).$$
其中 \(N_{\text{space}}\) 表示空格数量,\(N_{\text{letter}}\) 表示英文大小写字母数量,\(W_{\text{word}}\) 表示相应英文单词在两侧带空格时出现的次数。
因此最终选出的密钥是
$$k^\star=\operatorname*{arg\,max}_{k\in K} S(p(k)).$$
这就是代码真正实现的数学对象。它并不是把三个密钥位置分别求出来,而是始终对完整解密后的文本整体打分。
实现里带有一个很小的校验例子,明文是 “hello world”,密钥是 “abc”。把密钥字节写成 \(97,98,99\) 后,前几个加密值为
$$104\oplus97=9,\qquad 101\oplus98=7,\qquad 108\oplus99=15,$$
继续按同样的 3 周期模式进行,就得到密文前缀 \([9,7,15,13,13,67,\dots]\)。再用同一个循环密钥解密,过程会完全反向:
$$9\oplus97=104,\qquad 7\oplus98=101,\qquad 15\oplus99=108.$$
于是原始文本被精确恢复。错误的密钥有时也会生成看似可打印的字符,但通常得分会低很多,因为其中的字母更少、空格更少,而且几乎没有常见英文单词。
当最高分文本 \(p(k^\star)\) 被确定之后,题目要求的答案就是
$$A=\sum_{i=0}^{n-1} p_i(k^\star).$$
搜索阶段负责找出正确文本,最后这一步只是把该文本转换成题目要求的整数。
C++、Python 和 Java 实现都会把输入当作原始文本逐字符扫描。连续的十进制数字会被收集成一个完整 token,转成整数后加入密文数组;逗号和换行只起分隔作用。
随后,程序遍历所有由小写字母组成的三元组。对每一个三元组,都用长度为 3 的循环 XOR 规则解密整段密文,并把结果构造成候选明文字符串。
每个候选明文先经过 ASCII 范围过滤,再按上述英文评分函数计算分数。只要当前候选超过此前见过的最佳分数,程序就把它保存为新的最优文本。完整的 \(26^3\) 搜索结束后,再对这个最优文本的 ASCII 码求和。主搜索开始前,三个实现还都会用一个短样例验证 XOR 的往返可逆性。
设密文字节数为 \(n\)。解析输入需要 \(O(n)\) 时间。穷举阶段会测试 \(26^3\) 个密钥,而每个密钥都要花 \(O(n)\) 时间完成解密与评分,因此主导时间复杂度是
$$O(26^3 n).$$
由于 \(26^3=17{,}576\) 是固定常数,所以总运行时间对消息长度而言是线性的,只是常数因子中等。评分里对四个固定短词的额外查找仍然是线性的,不会改变渐近数量级。
空间复杂度为 \(O(n)\)。程序需要保存密文、当前构造的一个候选明文,以及少量与最佳分数和密钥枚举相关的常数级辅助信息。
Шифртекст задан как список ASCII-кодов, разделенных запятыми. Он получен из английского текста с помощью XOR-шифрования повторяющимся ключом длины 3. Каждый символ ключа является строчной английской буквой, поэтому всего существует лишь \(26^3\) допустимых ключей. Нужно восстановить правильный открытый текст, а затем вычислить сумму его ASCII-значений.
Решающими являются три факта: XOR обратим сам к себе, ключ повторяется через каждые три позиции, а реализации не используют отдельный криптоаналитический трюк. Вместо этого они перебирают все допустимые ключи и сравнивают полученные расшифровки по явной функции оценки английского текста.
Обозначим шифртекст через \(e_0,e_1,\dots,e_{n-1}\). Для ключа-кандидата \(k=(k_0,k_1,k_2)\), где каждый \(k_r\in\{97,98,\dots,122\}\), расшифрованный байт в позиции \(i\) равен
$$p_i(k)=e_i \oplus k_{i \bmod 3}.$$
Тем самым вся задача превращается в конечную задачу оптимизации на множестве ключей \(K=\{97,\dots,122\}^3\).
Главная инвариантная формула имеет вид
$$x \oplus y \oplus y = x.$$
Если байт открытого текста \(p_i\) был зашифрован как \(e_i=p_i \oplus k_{i \bmod 3}\), то повторное применение того же ключевого байта возвращает исходный символ:
$$e_i \oplus k_{i \bmod 3}=(p_i \oplus k_{i \bmod 3}) \oplus k_{i \bmod 3}=p_i.$$
Никакой рекуррентной формулы здесь не требуется. Как только ключ фиксирован, каждый символ определяется независимо, а период 3 точно указывает, какой байт ключа используется в каждом индексе.
Так как длина ключа равна 3, а каждый его символ должен быть строчной ASCII-буквой, имеем
$$|K|=26^3=17{,}576.$$
Это число достаточно мало для прямого полного перебора. Для каждого ключа расшифровка требует лишь одного XOR на каждую позицию шифртекста, поэтому весь поиск остается практически мгновенным. Именно поэтому решению не нужна более сложная схема с отдельным анализом классов по модулю 3.
Метод точен относительно своей функции оценки: реализации не угадывают лучший ключ, а проверяют все возможные и сохраняют расшифровку с максимальным баллом.
Реализации сначала применяют жесткий фильтр допустимости, а затем взвешенную оценку английского текста. Если какой-либо расшифрованный символ выходит за пределы ASCII-диапазона от 9 до 126, кандидат получает очень большое отрицательное значение и фактически отбрасывается. Иначе оценка равна
$$S(p)=3N_{\text{space}}(p)+2N_{\text{letter}}(p)+40W_{\text{the}}(p)+25W_{\text{and}}(p)+20W_{\text{of}}(p)+20W_{\text{to}}(p).$$
Здесь \(N_{\text{space}}\) считает пробелы, \(N_{\text{letter}}\) считает заглавные и строчные английские буквы, а \(W_{\text{word}}\) считает вхождения указанного слова, записанного с пробелами по краям.
Следовательно, выбранный ключ определяется как
$$k^\star=\operatorname*{arg\,max}_{k\in K} S(p(k)).$$
Именно этот объект фактически реализован в коде. Три позиции ключа не восстанавливаются по отдельности; всегда оценивается полностью расшифрованный текст.
В реализациях есть небольшой контрольный пример с открытым текстом “hello world” и ключом “abc”. Если записать байты ключа как \(97,98,99\), то первые зашифрованные значения равны
$$104\oplus97=9,\qquad 101\oplus98=7,\qquad 108\oplus99=15,$$
а дальнейшее повторение того же периода 3 дает префикс шифртекста \([9,7,15,13,13,67,\dots]\). При расшифровке тем же повторяющимся ключом процесс обращается:
$$9\oplus97=104,\qquad 7\oplus98=101,\qquad 15\oplus99=108.$$
Исходный текст восстанавливается точно. Неверный ключ иногда тоже порождает печатаемые символы, но почти всегда получает намного меньший балл, потому что содержит меньше букв, меньше пробелов и почти не содержит распространенных английских слов.
Когда найден текст \(p(k^\star)\) с максимальной оценкой, искомая величина задачи равна просто
$$A=\sum_{i=0}^{n-1} p_i(k^\star).$$
Поиск определяет правильную расшифровку, а заключительная сумма переводит ее в требуемое целое число.
Реализации на C++, Python и Java читают вход как сырой текст и проходят по нему посимвольно. Последовательные десятичные цифры объединяются в один токен, преобразуются в целое число и добавляются в массив шифртекста. Запятые и переводы строк служат только разделителями.
Затем программа перебирает все тройки строчных букв. Для каждой тройки она расшифровывает весь шифртекст по периодическому XOR-правилу длины 3 и строит строку-кандидат открытого текста.
Каждый кандидат сначала проверяется фильтром ASCII-диапазона, а потом оценивается взвешенной английской функцией. Если текущий кандидат превосходит лучший результат, найденный ранее, он сохраняется как новый лидер. После завершения полного перебора \(26^3\) ключей реализации суммируют ASCII-коды лучшего текста. Перед основным поиском они также проверяют обратимость XOR на коротком известном примере.
Пусть \(n\) обозначает число байтов в шифртексте. Разбор входа занимает \(O(n)\). Полный перебор рассматривает \(26^3\) ключей, и для каждого требуется \(O(n)\) работы на расшифровку и оценку, так что доминирующая сложность равна
$$O(26^3 n).$$
Поскольку \(26^3=17{,}576\) является фиксированной константой, время работы линейно по длине сообщения с умеренным постоянным множителем. Дополнительные проходы для подсчета четырех фиксированных коротких слов не меняют асимптотической оценки.
Память равна \(O(n)\): хранятся шифртекст, один текущий вариант открытого текста и постоянный объем служебной информации для лучшего балла и перебора ключей.
النص المشفر معطى على هيئة قائمة من أعداد ASCII مفصولة بفواصل. وقد نتج من نص إنجليزي عادي بعد تطبيق XOR بمفتاح دوري طوله 3. كل حرف في المفتاح هو حرف إنجليزي صغير، ولذلك فإن عدد المفاتيح الممكنة لا يتجاوز \(26^3\). المطلوب هو استعادة النص الصحيح ثم حساب مجموع قيم ASCII الخاصة به.
هناك ثلاث حقائق تحكم الحل بالكامل: عملية XOR هي معكوس نفسها، والمفتاح يتكرر كل ثلاث خانات، والتنفيذات لا تستخدم اختصارًا تحليليًا منفصلًا. بدلًا من ذلك فهي تجرب كل مفتاح مسموح وتفاضل بين النصوص الناتجة عبر دالة صريحة تقيس مدى شبهها بالنص الإنجليزي.
لنرمز إلى النص المشفر بـ \(e_0,e_1,\dots,e_{n-1}\). وإذا أخذنا مفتاحًا مرشحًا \(k=(k_0,k_1,k_2)\) بحيث يكون كل \(k_r\in\{97,98,\dots,122\}\)، فإن البايت المفكوك في الموضع \(i\) يساوي
$$p_i(k)=e_i \oplus k_{i \bmod 3}.$$
وبذلك تتحول المسألة كلها إلى مسألة تحسين منتهية على مجموعة المفاتيح \(K=\{97,\dots,122\}^3\).
الثابت الأساسي هو
$$x \oplus y \oplus y = x.$$
فإذا كان بايت من النص العادي \(p_i\) قد شُفِّر وفق العلاقة \(e_i=p_i \oplus k_{i \bmod 3}\)، فإن تطبيق بايت المفتاح نفسه مرة أخرى يعيد الرمز الأصلي:
$$e_i \oplus k_{i \bmod 3}=(p_i \oplus k_{i \bmod 3}) \oplus k_{i \bmod 3}=p_i.$$
لا توجد هنا علاقة عودية نحتاج إلى حلها. ما إن يثبت المفتاح حتى تصبح كل خانة محددة بصورة مستقلة، ويخبرنا الدور 3 مباشرة بأي بايت من المفتاح نستخدمه عند كل موضع.
بما أن طول المفتاح هو 3 وكل حرف فيه يجب أن يكون حرف ASCII صغيرًا، فإن
$$|K|=26^3=17{,}576.$$
وهذا عدد صغير بما يكفي لإجراء بحث شامل مباشر. فك التشفير لكل مفتاح لا يتطلب إلا عملية XOR واحدة لكل موضع من النص المشفر، ولذلك يبقى البحث كله عمليًا جدًا. ولهذا لا تحتاج الحلول إلى بناء أكثر تعقيدًا يعتمد على تحليل كل فئة باقية على حدة.
الطريقة دقيقة بالنسبة إلى معيارها في التقييم: فهي لا تخمن أفضل مفتاح، بل تمر على جميع المفاتيح الممكنة ثم تختار النص الأعلى درجة.
تستخدم التنفيذات أولًا مرشح صلاحية صارمًا، ثم درجة موزونة للنص الإنجليزي. فإذا ظهر أي محرف مفكوك خارج مجال ASCII من 9 إلى 126، يُمنح المرشح قيمة سالبة كبيرة جدًا فيُستبعد عمليًا. وإذا كان النص صالحًا، فإن الدرجة تُعطى بالعلاقة
$$S(p)=3N_{\text{space}}(p)+2N_{\text{letter}}(p)+40W_{\text{the}}(p)+25W_{\text{and}}(p)+20W_{\text{of}}(p)+20W_{\text{to}}(p).$$
حيث يعد \(N_{\text{space}}\) عدد الفراغات، ويعد \(N_{\text{letter}}\) عدد الحروف الإنجليزية الصغيرة والكبيرة، ويعد \(W_{\text{word}}\) عدد مرات ظهور الكلمة المحددة عندما تكون محاطة بفراغات.
ومن ثم يكون المفتاح المختار هو
$$k^\star=\operatorname*{arg\,max}_{k\in K} S(p(k)).$$
وهذا هو الكائن الرياضي الحقيقي الذي تنفذه الشيفرة. فهي لا تستخرج أحرف المفتاح الثلاثة كلًا على حدة، بل تقيم النص المفكوك كاملًا في كل مرة.
تحتوي التنفيذات على اختبار صغير يستخدم النص “hello world” والمفتاح “abc”. وإذا كتبنا بايتات المفتاح على صورة \(97,98,99\)، فإن أول القيم المشفرة تكون
$$104\oplus97=9,\qquad 101\oplus98=7,\qquad 108\oplus99=15,$$
ومع متابعة النمط الدوري نفسه بطول 3 نحصل على بادئة النص المشفر \([9,7,15,13,13,67,\dots]\). وعند فك التشفير بالمفتاح الدوري نفسه تنعكس العملية تمامًا:
$$9\oplus97=104,\qquad 7\oplus98=101,\qquad 15\oplus99=108.$$
وهكذا نستعيد النص الأصلي بدقة. أما المفتاح الخاطئ فقد ينتج أحيانًا محارف قابلة للطباعة، لكنه غالبًا ما يحصل على درجة أقل بكثير لأنه يحتوي على حروف أقل وفراغات أقل وعدد أقل من الكلمات الإنجليزية الشائعة.
بعد تحديد النص الأفضل \(p(k^\star)\)، تصبح الإجابة المطلوبة في المسألة هي فقط
$$A=\sum_{i=0}^{n-1} p_i(k^\star).$$
مرحلة البحث تحدد النص الصحيح، ثم تحول الخطوة الأخيرة هذا النص إلى العدد الصحيح الذي يطلبه السؤال.
تقرأ تنفيذات C++ وPython وJava المدخل على أنه نص خام ثم تمر عليه محرفًا محرفًا. تُجمع الأرقام العشرية المتتالية في رمز واحد، ثم تُحوَّل إلى عدد صحيح وتُضاف إلى مصفوفة النص المشفر. أما الفواصل ونهايات الأسطر فليست إلا فواصل بين القيم.
بعد ذلك تمر الشيفرة على جميع الثلاثيات الممكنة من الحروف الصغيرة. ولكل ثلاثية تفك الرسالة كلها باستخدام قاعدة XOR الدورية ذات الطول 3، ثم تبني النص المفكوك المرشح على هيئة سلسلة محارف.
يمر كل نص مرشح أولًا عبر مرشح مجال ASCII ثم يحصل على درجته الموزونة الخاصة بالنص الإنجليزي. وكلما تجاوز مرشح ما أفضل درجة شوهدت حتى تلك اللحظة، يُحفظ على أنه النص الأفضل الحالي. وبعد اكتمال البحث على جميع المفاتيح \(26^3\)، تُجمع قيم ASCII الخاصة بالنص الفائز. وقبل بدء البحث الرئيسي، تتحقق التنفيذات أيضًا من خاصية الذهاب والإياب لعملية XOR على مثال قصير معروف.
إذا كان \(n\) هو عدد بايتات النص المشفر، فإن تحليل الإدخال يحتاج إلى \(O(n)\). والبحث الشامل يجرب \(26^3\) مفتاحًا، وكل مفتاح يحتاج إلى \(O(n)\) عملًا لفك التشفير والتقييم، ولذلك يكون الزمن الغالب هو
$$O(26^3 n).$$
وبما أن \(26^3=17{,}576\) ثابتة، فإن زمن التنفيذ خطي في طول الرسالة مع ثابت معتدل. كما أن عمليات عد الكلمات الإضافية تتعلق بأربع كلمات قصيرة ثابتة، ولذلك لا تغير الرتبة التقاربية.
استهلاك الذاكرة هو \(O(n)\)، لأن التنفيذ يحتفظ بالنص المشفر، وبنص مرشح واحد في كل مرة، وبقدر ثابت من البيانات المساعدة الخاصة بأفضل درجة وتعداد المفاتيح.