<commit_before>"""Automated breaking of the Simple Substitution cipher"""
import random
import math
import string

from pycipher import SimpleSubstitution
from cckrypto.score import score


def crack(ciphertext, score_functions, nswaps=3000, ntrials=30):
    key = list(string.ascii_lowercase)
    decryptions = []
    best_score = -99e9

    # Find global maximums
    for iteration in range(ntrials):
        random.shuffle(key)
        best_trial_score = -99e9

        for swap in range(nswaps):
            new_key = key[:]

            # Swap 2 characters in the key
            a, b = random.sample(range(26), 2)
            new_key[a], new_key[b] = new_key[b], new_key[a]

            plaintext = SimpleSubstitution(new_key).decipher(ciphertext, keep_punct=True)
            new_score = score(plaintext, score_functions)

            # Keep track of best score for a single trial
            if new_score > best_trial_score:
                key = new_key[:]
                best_trial_score = new_score

        # Keep track of the best score over all trials
        if best_trial_score > best_score:
            best_key = key[:]
            best_score = best_trial_score
            decryptions.append(
                (SimpleSubstitution(best_key).decipher(ciphertext, keep_punct=True), best_score)
            )

    return sorted(decryptions, key=lambda x: x[1], reverse=True)<commit_msg>Custom decipher function for simple substitution for speed increase<commit_after>"""Automated breaking of the Simple Substitution cipher"""
import random
import string

from cckrypto.score import score


def _decipher(key, ciphertext):
    rev_map = {v: k for k, v in zip(key, string.ascii_uppercase)}
    return ''.join((rev_map[char] if char in rev_map else char for char in ciphertext))


def crack(ciphertext, score_functions, nswaps=3000, ntrials=30):
    ciphertext = ciphertext.upper()
    key = list(string.ascii_uppercase)
    decryptions = []
    best_score = -99e9  # TODO: I Don't like this magic number

    # Find global maximums
    for iteration in range(ntrials):
        random.shuffle(key)
        best_trial_score = -99e9

        for swap in range(nswaps):
            new_key = key[:]

            # Swap 2 characters in the key
            a, b = random.sample(range(26), 2)  # TODO: More magic numbers :(
            new_key[a], new_key[b] = new_key[b], new_key[a]

            plaintext = _decipher(new_key, ciphertext)
            new_score = score(plaintext, score_functions)

            # Keep track of best score for a single trial
            if new_score > best_trial_score:
                key = new_key[:]
                best_trial_score = new_score

        # Keep track of the best score over all trials
        if best_trial_score > best_score:
            best_key = key[:]
            best_score = best_trial_score
            decryptions.append(
                (_decipher(best_key, ciphertext), best_score)
            )

    return sorted(decryptions, key=lambda x: x[1], reverse=True)
{'fraction_non_alphanumeric': 0.0828656322218554, 'fraction_numerical': 0.011224826675470452, 'mean_word_length': 2.4827586206896552, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1673476', 'n_tokens_mistral': 955, 'n_tokens_neox': 880, 'n_words': 256}