X-Git-Url: https://git.njae.me.uk/?a=blobdiff_plain;f=cipher.py;h=7b0b13f9ece0c87f995fc2d80e4690ba60588456;hb=64087b00d5935d7c87182494b9e2cdbc432bc9b6;hp=7fffd522759f3aa7cf74084480ca0099c19f59ef;hpb=37cc0fd10156888d8ea222fc511643be7b9dd436;p=cipher-tools.git diff --git a/cipher.py b/cipher.py index 7fffd52..7b0b13f 100644 --- a/cipher.py +++ b/cipher.py @@ -12,7 +12,7 @@ from multiprocessing import Pool # import timeit # c5a = open('2012/5a.ciphertext', 'r').read() # timeit.timeit('keyword_break(c5a)', setup='gc.enable() ; from __main__ import c5a ; from cipher import keyword_break', number=1) - +# timeit.repeat('keyword_break_mp(c5a, chunksize=500)', setup='gc.enable() ; from __main__ import c5a ; from cipher import keyword_break_mp', repeat=5, number=1 logger = logging.getLogger(__name__) logger.addHandler(logging.FileHandler('cipher.log')) @@ -406,7 +406,6 @@ def affine_break(message, metric=norms.euclidean_distance, target_counts=normali logger.info('Affine break best fit with key {0}x+{1} ({2}) gives fit of {3} and decrypt starting: {4}'.format(best_multiplier, best_adder, best_one_based, best_fit, affine_decipher(sanitised_message, best_multiplier, best_adder, best_one_based)[:50])) return (best_multiplier, best_adder, best_one_based), best_fit - def keyword_break(message, wordlist=keywords, metric=norms.euclidean_distance, target_counts=normalised_english_counts, message_frequency_scaling=norms.normalise): """Breaks a keyword substitution cipher using a dictionary and frequency analysis @@ -429,16 +428,15 @@ def keyword_break(message, wordlist=keywords, metric=norms.euclidean_distance, t logger.info('Keyword break best fit with key {0} (wrap={1}) gives fit of {2} and decrypt starting: {3}'.format(best_keyword, best_wrap_alphabet, best_fit, sanitise(keyword_decipher(message, best_keyword))[:50])) return (best_keyword, best_wrap_alphabet), best_fit -def keyword_break_mp(message, wordlist=keywords, metric=norms.euclidean_distance, target_counts=normalised_english_counts, message_frequency_scaling=norms.normalise): +def keyword_break_mp(message, wordlist=keywords, metric=norms.euclidean_distance, target_counts=normalised_english_counts, message_frequency_scaling=norms.normalise, chunksize=500): """Breaks a keyword substitution cipher using a dictionary and frequency analysis >>> keyword_break_mp(keyword_encipher('this is a test message for the keyword decipherment', 'elephant', 1), wordlist=['cat', 'elephant', 'kangaroo']) # doctest: +ELLIPSIS (('elephant', 1), 0.41643991598441...) """ with Pool() as pool: - keys = [(word, wrap) for word in wordlist for wrap in range(3)] - # breaks = map(lambda kw: keyword_break_one(message, kw[0], kw[1], metric, target_counts, message_frequency_scaling), keys) - breaks = pool.starmap(lambda k, w: keyword_break_one(message, k, w, metric, target_counts, message_frequency_scaling), keys, 1000) + helper_args = [(message, word, wrap, metric, target_counts, message_frequency_scaling) for word in wordlist for wrap in range(3)] + breaks = pool.starmap(keyword_break_one, helper_args, chunksize) # Gotcha: the helper function here needs to be defined at the top level (limitation of Pool.starmap) return min(breaks, key=lambda k: k[1]) def keyword_break_one(message, keyword, wrap_alphabet, metric, target_counts, message_frequency_scaling): @@ -448,7 +446,6 @@ def keyword_break_one(message, keyword, wrap_alphabet, metric, target_counts, me logger.debug('Keyword break attempt using key {0} (wrap={1}) gives fit of {2} and decrypt starting: {3}'.format(keyword, wrap_alphabet, fit, sanitise(plaintext)[:50])) return (keyword, wrap_alphabet), fit - def scytale_break(message, metric=norms.euclidean_distance, target_counts=normalised_english_bigram_counts, message_frequency_scaling=norms.normalise): """Breaks a Scytale cipher