Загрузка данных


import hashlib
from collections import Counter

text = """ьооьчосштицрувюунхэонпбиыойбшядйафаайихькгшщтнтввуячньвтъьчцабнпютэфттк
шзшудншщскуеоюппщхмечэпщбэмшпчхрвмшпяцэпаячхкьртпшсёртеьусуэфкайёпсрмп
... (вставь весь текст) ..."""

# Приводим к нижнему регистру, убираем всё кроме русских букв
alphabet = "абвгдеёжзийклмнопрстуфхцчшщъыьэюя"
text = ''.join(c for c in text.lower() if c in alphabet)

# ---------- 1. Индекс совпадений для поиска длины ключа ----------
def index_of_coincidence(s):
    n = len(s)
    if n < 2: return 0
    freq = Counter(s)
    return sum(v*(v-1) for v in freq.values()) / (n*(n-1))

def find_key_length(text, max_len=40):
    results = []
    for L in range(1, max_len+1):
        groups = [text[i::L] for i in range(L)]
        ic = sum(index_of_coincidence(g) for g in groups) / L
        results.append((L, ic))
    results.sort(key=lambda x: -x[1])
    return results[:10]

print("Возможные длины ключа (по индексу совпадений):")
for L, ic in find_key_length(text):
    print(f"  L={L:3d}  IC={ic:.4f}")

# ---------- 2. Частотный анализ по каждой позиции ----------
rus_freq = "оеаинтсрвлкмдпуяызьгбчйхжшюцщэфъё"
def break_caesar(segment):
    best_shift, best_score = 0, -1e9
    for shift in range(len(alphabet)):
        decrypted = ''.join(alphabet[(alphabet.index(c) - shift) % len(alphabet)] for c in segment)
        score = sum(decrypted.count(ch) * (len(rus_freq) - rus_freq.index(ch)) for ch in rus_freq if ch in decrypted)
        if score > best_score:
            best_score, best_shift = score, shift
    return best_shift

def recover_key(text, L):
    key = ""
    for i in range(L):
        segment = text[i::L]
        shift = break_caesar(segment)
        key += alphabet[shift]
    return key

# Попробуй топ-5 длин и покажи результаты
for L, _ in find_key_length(text)[:5]:
    key = recover_key(text, L)
    print(f"\nL={L} → ключ-кандидат: {key}")
    # если есть хеш, проверь:
    # print("  sha256:", hashlib.sha256(key.encode()).hexdigest())