From 1b742ef273fc82513715f84fbe9941758ce29d52 Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Mon, 21 Apr 2014 12:57:01 +0100 Subject: [PATCH] Trials for best metrics for affine cipher breaks --- affine_break_parameter_trials.csv | 10 ++++ find_best_affine_break_parameters.py | 85 ++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 affine_break_parameter_trials.csv create mode 100644 find_best_affine_break_parameters.py diff --git a/affine_break_parameter_trials.csv b/affine_break_parameter_trials.csv new file mode 100644 index 0000000..75f3f16 --- /dev/null +++ b/affine_break_parameter_trials.csv @@ -0,0 +1,10 @@ +"name",500,250,100,50,20 +"Pletters",2442,2425,2550,2461,2067 +"cosine_similarity + euclidean_scaled",2487,2492,2513,2455,1731 +"cosine_similarity + normalised",2503,2573,2454,2435,1680 +"l1 + euclidean_scaled",2495,2477,2506,2419,1812 +"l1 + normalised",2488,2521,2465,2466,1895 +"l2 + euclidean_scaled",2524,2467,2529,2470,1763 +"l2 + normalised",2566,2545,2481,2433,1756 +"l3 + euclidean_scaled",2444,2458,2560,2426,1582 +"l3 + normalised",2476,2524,2463,2354,1433 diff --git a/find_best_affine_break_parameters.py b/find_best_affine_break_parameters.py new file mode 100644 index 0000000..e3d6bad --- /dev/null +++ b/find_best_affine_break_parameters.py @@ -0,0 +1,85 @@ +import random +import collections +from cipher import * +from cipherbreak import * +import itertools +import csv + +corpus = sanitise(''.join([open('shakespeare.txt', 'r').read(), + open('sherlock-holmes.txt', 'r').read(), + open('war-and-peace.txt', 'r').read()])) +corpus_length = len(corpus) + +euclidean_scaled_english_counts = norms.euclidean_scale(english_counts) + +metrics = [{'func': norms.l1, 'invert': True, 'name': 'l1'}, + {'func': norms.l2, 'invert': True, 'name': 'l2'}, + {'func': norms.l3, 'invert': True, 'name': 'l3'}, + {'func': norms.cosine_similarity, 'invert': False, 'name': 'cosine_similarity'}] + # {'func': norms.harmonic_mean, 'invert': True, 'name': 'harmonic_mean'}, + # {'func': norms.geometric_mean, 'invert': True, 'name': 'geometric_mean'}] +scalings = [{'corpus_frequency': normalised_english_counts, + 'scaling': norms.normalise, + 'name': 'normalised'}, + {'corpus_frequency': euclidean_scaled_english_counts, + 'scaling': norms.euclidean_scale, + 'name': 'euclidean_scaled'}] +message_lengths = [2000, 1000, 500, 250, 100, 50, 20] + +trials = 5000 + +scores = {} + + +def make_frequency_compare_function(target_frequency, frequency_scaling, metric, invert): + def frequency_compare(text): + counts = frequency_scaling(frequencies(text)) + if invert: + score = -1 * metric(target_frequency, counts) + else: + score = metric(target_frequency, counts) + return score + return frequency_compare + +def scoring_functions(): + return [{'func': make_frequency_compare_function(s['corpus_frequency'], + s['scaling'], m['func'], m['invert']), + 'name': '{} + {}'.format(m['name'], s['name'])} + for m in metrics + for s in scalings] + [{'func': Pletters, 'name': 'Pletters'}] + +def eval_scores(): + [eval_one_score(f, l) + for f in scoring_functions() + for l in message_lengths] + +def eval_one_score(scoring_function, message_length): + print(scoring_function['name'], message_length, ': ', end='', flush=True) + if scoring_function['name'] not in scores: + scores[scoring_function['name']] = collections.defaultdict(int) + for _ in range(trials): + sample_start = random.randint(0, corpus_length - message_length) + sample = corpus[sample_start:(sample_start + message_length)] + multiplier = random.choice([x for x in range(1, 26, 2) if x != 13]) + adder = random.randint(0, 25) + one_based = random.choice([True, False]) + key = (multiplier, adder, one_based) + ciphertext = affine_encipher(sample, multiplier, adder, one_based) + found_key, _ = affine_break(ciphertext, scoring_function['func']) + if found_key == key: + scores[scoring_function['name']][message_length] += 1 + print(scores[scoring_function['name']][message_length], '/', trials) + return scores[scoring_function['name']][message_length] + +def show_results(): + with open('affine_break_parameter_trials.csv', 'w') as f: + writer = csv.DictWriter(f, ['name'] + message_lengths, + quoting=csv.QUOTE_NONNUMERIC) + writer.writeheader() + for scoring in sorted(scores.keys()): + scores[scoring]['name'] = scoring + writer.writerow(scores[scoring]) + +print('Starting...') +eval_scores() +show_results() -- 2.34.1