def break_bounded_length_code_with_mcmc_monogram_criteria( encryption, alphabet, n_list, coefs, log_distributions, steps_constant, lower_bound, upper_bound, monogram_log_distribution, scrabble): max_weight = float("-inf") max_state = [cipher.get_zero_mono_key()] for length in range(lower_bound, upper_bound + 1): state = get_max_monogram_state(encryption, monogram_log_distribution, length, alphabet)[0] if length > (lower_bound + upper_bound) / 2: state = break_fixed_length_code_with_mcmc( encryption, alphabet, state, n_list, coefs, log_distributions, int(steps_constant * alphabet.length * length * (2 + log(length))))[0] words_list = cipher.encrypt_decrypt_text(encryption, state, alphabet).get_words_list() weight = sum([word in scrabble for word in words_list]) / len(words_list) if weight > max_weight: max_weight = weight max_state = state if max_weight > 0.5: break return break_fixed_length_code_with_mcmc( encryption, alphabet, max_state, n_list, coefs, log_distributions, int(steps_constant * alphabet.length * len(max_state) * (10 + log(len(max_state)))))
def get_max_bigram_state(encryption, bigram_log_distribution, key_length, alphabet): all_mono_keys = cipher.get_all_mono_keys(alphabet) codes = { a: { b: [cipher.get_zero_mono_key() for i in range(key_length - 1)] for b in all_mono_keys } for a in all_mono_keys } values = { a: { b: get_bigram_part_weight(encryption, (a, b), 0, key_length, bigram_log_distribution, alphabet) for b in all_mono_keys } for a in all_mono_keys } new_values = {a: {b: 0 for b in all_mono_keys} for a in all_mono_keys} for r in range(1, key_length): for i in all_mono_keys: for j in codes[i]: max_func = float("-inf") max_arg = cipher.get_zero_mono_key() for k in codes[i]: func = values[i][k] + get_bigram_part_weight( encryption, (k, j), r, key_length, bigram_log_distribution, alphabet) if func > max_func: max_func = func max_arg = k new_values[i][j] = max_func codes[i][j][r - 1] = max_arg aux = values values = new_values new_values = aux return get_max_bigram_key_and_weight(values, codes, all_mono_keys)
def get_max_monogram_state_coord(encryption, coordinate, monogram_log_distribution, key_length, alphabet): max_state = cipher.get_zero_mono_key() max_weight = float("-inf") for j in cipher.get_all_mono_keys(alphabet): weight = 0 for i in range(coordinate, len(encryption), key_length): weight += monogram_log_distribution[cipher.encrypt_decrypt_single( encryption[i], j, alphabet)] if weight > max_weight: max_state = j max_weight = weight return max_state, max_weight
def break_bounded_length_code_with_mcmc(encryption, alphabet, n_list, coefs, distributions, steps, boundary, monogram_log_distribution): max_weight = float("-inf") max_state = [cipher.get_zero_mono_key()] for length in range(1, boundary + 1): start = get_max_monogram_state(encryption, monogram_log_distribution, length, alphabet)[0] break_attempt = break_fixed_length_code_with_mcmc( encryption, alphabet, start, n_list, coefs, distributions, steps) if break_attempt[1] > max_weight: max_state = break_attempt[0] max_weight = break_attempt[1] return max_state, max_weight
def get_max_bigram_key_and_weight(values, codes, all_mono_keys): max_bigram_weight_value = -float("inf") max_state = cipher.get_zero_mono_key() for i in all_mono_keys: if values[i][i] > max_bigram_weight_value: max_bigram_weight_value = values[i][i] max_state = i bigram_maximizer = [] t = len(codes[max_state][max_state]) - 1 current = max_state for i in range(len(codes[max_state][max_state])): current = codes[max_state][current][t] bigram_maximizer.append(current) t -= 1 bigram_maximizer.append(max_state) bigram_maximizer.reverse() return bigram_maximizer, max_bigram_weight_value