Python script for D'Agapeyeff cipher decryption

# Paste this into a Python environment (Python 3.8+). No external internet needed. # Replace CIPHER with the exact ciphertext string (digits or letters). import math from collections import Counter, defaultdict import itertools import random # ------------------------- CIPHER = "PASTE_CIPHERTEXT_HERE" # <-- replace this with the D'Agapeyeff ciphertext # ------------------------- # Basic normalization text_raw = "".join(CIPHER.strip().split()) # If digits, keep digits and maybe split into pairs/triples; if letters, uppercase letters only. is_digit = all(ch.isdigit() for ch in text_raw) is_alpha = all(ch.isalpha() for ch in text_raw) def split_digits(text, group=2): return [text[i:i+group] for i in range(0,len(text),group)] def freq_stats(s): c = Counter(s) total = len(s) freqs = [(ch, count, count/total) for ch,count in c.most_common()] return freqs print("Raw length:", len(text_raw)) print("All digits?", is_digit, "All letters?", is_alpha) if is_digit: for g in (1,2,3): groups = split_digits(text_raw, g) print(f"\nGrouping by {g} -> {len(groups)} tokens. Sample:", groups[:20]) print("Frequencies:", freq_stats(groups)[:10]) else: letters = [c.upper() for c in text_raw if c.isalpha()] print("\nLetter sample:", "".join(letters[:80])) print("Letter frequencies:", freq_stats(letters)[:20]) # compute Index of Coincidence N = len(letters) ic = sum(v*(v-1) for v in Counter(letters).values()) / (N*(N-1)) if N>1 else 0 print("Index of Coincidence:", ic) # ------------------------- # Quick Vigenere bruteforce using english quadgram scoring # ------------------------- # Quadgram statistics small sample (for speed). For best results replace with a full quadgram table. quadgrams = { 'TION': 1.0, 'THER':0.9, 'HERE':0.8, 'MENT':0.7, 'ENTH':0.6, # not exhaustive } def score_text_quads(s): s = "".join(ch for ch in s.upper() if ch.isalpha()) score = 0.0 for i in range(len(s)-3): w = s[i:i+4] score += math.log10(quadgrams.get(w, 0.01)) return score def vigenere_decrypt(ct, key): res = [] ki = 0 for ch in ct: if ch.isalpha(): offset = ord('A') k = ord(key[ki%len(key)].upper())-offset p = chr((ord(ch.upper())-offset - k) % 26 + offset) res.append(p) ki += 1 else: res.append(ch) return "".join(res) def try_vigenere(ct, max_keylen=10): ct_letters = "".join(ch for ch in ct.upper() if ch.isalpha()) best = [] for klen in range(1, max_keylen+1): for key_candidate in itertools.product("ABCDEFGHIJKLMNOPQRSTUVWXYZ", repeat=klen): key = "".join(key_candidate) pt = vigenere_decrypt(ct_letters, Had to remove some of the code due to 3000 word limit 🥺🤔🤐🥴 having a nerd 🤓 moment. Things are different 🤫

To view or add a comment, sign in

Explore content categories