diff --git a/HeuristicLib.py b/HeuristicLib.py new file mode 100755 index 0000000..bbe0812 --- /dev/null +++ b/HeuristicLib.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +import re +from RuneText import RuneText +from NGrams import NGrams + + +def normalized_probability(int_prob): + total = sum(int_prob) + return [x / total for x in int_prob] # math.log(x / total, 10) + + +RUNES = 'ᚠᚢᚦᚩᚱᚳᚷᚹᚻᚾᛁᛄᛇᛈᛉᛋᛏᛒᛖᛗᛚᛝᛟᛞᚪᚫᚣᛡᛠ' +re_norune = re.compile('[^' + RUNES + ']') +PROB_INT = [0] * 29 +for k, v in NGrams.load().items(): + PROB_INT[RUNES.index(k)] = v +PROB_NORM = normalized_probability(PROB_INT) +K_r = 1 / 29 # 0.034482758620689655 +K_p = sum(x ** 2 for x in PROB_INT) # 0.06116195419412538 + + +######################################### +# Probability : Count runes and do simple frequency analysis +######################################### + +class Probability(object): + def __init__(self, numstream): + self.prob = [0] * 29 + for r in numstream: + self.prob[r] += 1 + self.N = len(numstream) + + def IC(self): + X = sum(x * (x - 1) for x in self.prob) + return X / ((self.N * (self.N - 1)) / 29) + + def friedman(self): + return (K_p - K_r) / (self.IC() - K_r) + + def similarity(self): + probs = normalized_probability(self.prob) + return sum((x - y) ** 2 for x, y in zip(PROB_NORM, probs)) + + @staticmethod + def IC_w_keylen(nums, keylen): + val = sum(Probability(nums[x::keylen]).IC() for x in range(keylen)) + return val / keylen + + +######################################### +# load page and convert to indices for faster access +######################################### + +def load_indices(fname, interrupt, maxinterrupt=None, minlen=None, limit=None): + with open(fname, 'r') as f: + data = RuneText(re_norune.sub('', f.read()))['index'][:limit] + if maxinterrupt is not None: + # incl. everything up to but not including next interrupt + # e.g., maxinterrupt = 0 will return text until first interrupt + for i, x in enumerate(data): + if x != interrupt: + continue + if maxinterrupt == 0: + if minlen and i < minlen: + continue + return data[:i] + maxinterrupt -= 1 + return data diff --git a/HeuristicSearch.py b/HeuristicSearch.py index 2015c94..5714b77 100755 --- a/HeuristicSearch.py +++ b/HeuristicSearch.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import itertools # product, compress, combinations import bisect # bisect_left, insort +import lib as LIB ######################################### @@ -26,6 +27,31 @@ class GuessVigenere(object): return found +######################################### +# GuessAffine : Find greatest common affine key +######################################### + +class GuessAffine(object): + def __init__(self, nums): + self.nums = nums + + def guess(self, keylength, score_fn): # minimize score_fn + found = [] + for offset in range(keylength): + candidate = (None, None) + best = 9999999 + for s in range(29): + for t in range(29): + shifted = [LIB.affine_decrypt(x, (s, t)) + for x in self.nums[offset::keylength]] + score = score_fn(shifted) + if score < best: + best = score + candidate = (s, t) + found.append(candidate) + return found + + ######################################### # SearchInterrupt : Hill climbing algorithm for interrupt detection ######################################### @@ -39,6 +65,9 @@ class SearchInterrupt(object): def to_occurrence_index(self, interrupts): return [self.stops.index(x) + 1 for x in interrupts] + def from_occurrence_index(self, interrupts): + return [self.stops[x - 1] for x in interrupts] + def join(self, interrupts=[]): # rune positions, not occurrence index ret = [] i = -1 @@ -145,7 +174,7 @@ class SearchInterrupt(object): current = update continue # did optimize, so retry with same level level += 1 - print() + print('.') # find equally likely candidates if self.single_result: return best, [current] diff --git a/InterruptDB.py b/InterruptDB.py new file mode 100755 index 0000000..eeeebee --- /dev/null +++ b/InterruptDB.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 +import os +from HeuristicSearch import SearchInterrupt +from HeuristicLib import load_indices, Probability + + +class InterruptDB(object): + DB_NAME = 'data/interruptDB.txt' + + def __init__(self, data, interrupt): + self.iguess = SearchInterrupt(data, interrupt) + self.stop_count = len(self.iguess.stops) + + def make(self, keylen): + def fn(x): + return Probability.IC_w_keylen(x, keylen) + score, intrpts = self.iguess.sequential(fn, startAt=0, maxdepth=99) + # score, intrpts = self.iguess.genetic(fn, topDown=False, maxdepth=4) + # score, intrpts = fn(self.iguess.join()), [[]] # without interrupts + for i, skips in enumerate(intrpts): + intrpts[i] = self.iguess.to_occurrence_index(skips) + return score, intrpts + + @staticmethod + def load(): + if not os.path.isfile(InterruptDB.DB_NAME): + return {} + ret = {} + with open(InterruptDB.DB_NAME, 'r') as f: + for line in f.readlines(): + if line.startswith('#'): + continue + line = line.rstrip() + name, irpc, score, irp, kl, nums = [x for x in line.split('|')] + val = [int(irpc), float(score), int(irp), int(kl)] + val.append([int(x) for x in nums.split(',')] if nums else []) + try: + ret[name].append(val) + except KeyError: + ret[name] = [val] + return ret + + @staticmethod + def write(fname, score, irpchr, irpmax, keylen, nums): + nums = ','.join(map(str, nums)) + with open(InterruptDB.DB_NAME, 'a') as f: + t = f'{fname}|{irpmax}|{score:.5f}|{irpchr}|{keylen}|{nums}\n' + f.write(t) + + +def populate_db(irp_chars=range(1), startkeylen=1, maxkeylen=32): + oldDB = InterruptDB.load() + oldValues = {k: set((a, b, c) for a, _, b, c, _ in v) + for k, v in oldDB.items()} + for name in [ + # '0_welcome', 'jpg107-167', '0_warning', '0_wisdom', + 'p0-2', 'p3-7', 'p8-14', 'p15-22', 'p23-26', + 'p27-32', 'p33-39', 'p40-53', 'p54-55' + ]: + fname = f'pages/{name}.txt' + print('load:', fname) + for irp in irp_chars: # interrupt rune index + data = load_indices(fname, irp, maxinterrupt=20) + db = InterruptDB(data, irp) + irp_count = db.stop_count + print('analyze interrupt:', irp, 'count:', irp_count) + for keylen in range(startkeylen, maxkeylen + 1): + if (irp_count, irp, keylen) in oldValues.get(name, []): + print(f'{keylen}: skipped.') + continue + score, interrupts = db.make(keylen) + print(f'{keylen}: {score:.4f}, solutions: {len(interrupts)}') + for x in interrupts: + InterruptDB.write(name, score, irp, irp_count, keylen, x) diff --git a/RuneSolver.py b/RuneSolver.py index 92df3bd..6594a5a 100755 --- a/RuneSolver.py +++ b/RuneSolver.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 from RuneRunner import RuneRunner from RuneText import Rune, RuneText +import lib as LIB ######################################### @@ -137,3 +138,38 @@ class SequenceSolver(RuneSolver): def __str__(self): return super().__str__() + f'\nf(x): {self.FN}' + + +######################################### +# AffineSolver : Decrypt runes with an array of (s, t) affine keys +######################################### + +class AffineSolver(RuneSolver): + def __init__(self): + super().__init__() + self.current_key_pos = 0 + self.reset() + + def reset(self): + super().reset() + self.KEY_DATA = [] # the key material + self.KEY_INVERT = False # ABCD -> ZYXW + + def run(self, data=None): + self.current_key_pos = 0 + super().run(data=data) + + def rotate_key(self): + self.current_key_pos = (self.current_key_pos + 1) % len(self.KEY_DATA) + + def cipher(self, rune, context): + r_idx = rune.index + if self.KEY_INVERT: + r_idx = 28 - r_idx + r_idx = LIB.affine_decrypt(r_idx, self.KEY_DATA[self.current_key_pos]) + self.rotate_key() + return Rune(i=r_idx) + + def __str__(self): + return super().__str__() + \ + f'\nkey: {self.KEY_DATA}\nkey invert: {self.KEY_INVERT}' diff --git a/data/interruptDB.txt b/data/interruptDB.txt new file mode 100644 index 0000000..b38d7fb --- /dev/null +++ b/data/interruptDB.txt @@ -0,0 +1,665 @@ +# file-name | number of interrupts | score | interrupt-rune (index) | key length | interrupts (starting with index 1 for first occurrence) +0_welcome|25|1.17420|0|1| +jpg107-167|5|1.13036|0|1| +0_warning|1|1.85685|0|1| +0_wisdom|5|1.52270|0|1| +p0-2|34|0.98839|0|1| +p3-7|26|1.00438|0|1| +p8-14|66|0.99935|0|1| +p15-22|72|1.00056|0|1| +p23-26|37|0.99396|0|1| +p27-32|52|0.99140|0|1| +p33-39|40|0.99644|0|1| +p40-53|125|1.00174|0|1| +p54-55|6|0.98082|0|1| +0_welcome|14|1.70031|0|8|1,4,5,6,7,11,12,14 +0_welcome|14|1.70031|0|8|1,4,5,6,7,10,12,14 +0_welcome|14|1.70031|0|8|1,3,5,6,7,11,12,14 +0_welcome|14|1.70031|0|8|1,3,5,6,7,10,12,14 +0_welcome|14|1.74248|0|12|4,5,6,8,11,12,14 +0_welcome|14|1.74248|0|12|4,5,6,8,10,12,14 +0_welcome|14|1.74248|0|12|3,5,6,8,11,12,14 +0_welcome|14|1.74248|0|12|3,5,6,8,10,12,14 +jpg107-167|5|1.19072|0|8|1,2,3 +jpg107-167|5|1.25971|0|9|1,4,5 +jpg107-167|5|1.19196|0|10|1,3,4,5 +jpg107-167|5|1.17869|0|11|1,3,4,5 +jpg107-167|5|1.09583|0|12|4 +jpg107-167|5|2.14768|0|13|2,3 +p0-2|20|1.02741|0|1|1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 +p0-2|20|1.09547|0|2|2,3,5,6,8,10,11,12,14,17,18,19,20 +p0-2|20|1.14150|0|3|1,2,5,7,9,11,14,15,16,17,18,19,20 +p0-2|20|1.13231|0|4|3,4,6,9,11,12,13,14 +p0-2|20|1.16489|0|5|1,2,3,4,5,9,12,13,19 +p0-2|20|1.16355|0|6|1,2,5,7,8,11,14,15,16,17,18,19,20 +p0-2|20|1.26817|0|7|1,3,5,6,7,9,11,13,14,15,17,18,19 +p0-2|20|1.16853|0|8|2,5,6,7,10,14,15,16,17,18,19 +p0-2|20|1.24714|0|9|1,2,3,7,8,13,14,15,16,17 +p0-2|20|1.21659|0|10|1,2,3,4,5,9,12,13,19 +p0-2|20|1.28945|0|11|1,3,5,6,10,11,12,13,14,15,16,17,18,19,20 +p0-2|20|1.29341|0|12|1,2,5,8,9,10,13,14,15,16,18,19,20 +p0-2|20|1.22812|0|13|1,3,4,5,7,8,9,10,11,12,13,14,15,16,19,20 +p0-2|20|1.34456|0|14|1,4,5,6,8,12,13,14,16,17,20 +p0-2|20|1.29400|0|15|1,3,4,5,7,9,13,14,15,16,17 +p0-2|20|1.25527|0|16|1,4,6,7,12,13,14,15,16,17,19,20 +p0-2|20|1.38448|0|17|1,2,5,6,8,9,12,15,16,17,19 +p0-2|20|1.36640|0|18|1,2,5,8,9,10,13,14,15,16,18,19,20 +p0-2|20|1.36640|0|18|1,2,4,8,9,10,13,14,15,16,18,19,20 +p0-2|20|1.27259|0|19|2,4,5,6,7,8,10,11,12,18,19,20 +p0-2|20|1.27259|0|19|2,3,5,6,7,8,9,11,12,18,19,20 +p0-2|20|1.30972|0|20|1,2,3,4,5,9,12,13,17 +p0-2|20|1.36319|0|21|1,4,5,6,7,12,14,15,16,20 +p0-2|20|1.36319|0|21|1,3,4,6,7,12,14,15,16,20 +p0-2|20|1.35038|0|22|1,2,4,5,6,9,10,12 +p0-2|20|1.36594|0|23|1,2,4,5,6,7,8,9,11,13,14,15,16,17,18,19 +p0-2|20|1.37714|0|24|5,7,8,10,13,15,16,17,18,19,20 +p0-2|20|1.37039|0|25|2,3,4,5,6,12,15,18 +p0-2|20|1.33846|0|26|1,2,3,4,5,7,8,9,10,11,13,14,15,16,17,18,20 +p0-2|20|1.32597|0|27|2,3,7,11,12,14,15,16,17 +p0-2|20|1.45607|0|28|2,3,5,6,8,9,11,13,14,15,17,18,20 +p0-2|20|1.49231|0|29|5,7,8,10,11,14,17 +p0-2|20|1.31545|0|30|1,2,7,8,10,11 +p0-2|20|1.40837|0|31|2,3,4,5,6,7,8,12,13,15,18,20 +p0-2|20|1.39740|0|32|1,2,3,4,5,6,7,8,9,10,11,12,13,14 +p3-7|20|1.03220|0|1|1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 +p3-7|20|1.07427|0|2|1,4,6,7,8,11,13,15,16,18,19,20 +p3-7|20|1.11940|0|3|1,2,3,6,10,11,12,13,14,15,16,17,18,19,20 +p3-7|20|1.08906|0|4|1,4,6,7,8,9,10,11,13,15,16,20 +p3-7|20|1.11979|0|5|1,2,3,4,5,6,9,13,20 +p3-7|20|1.12579|0|6|1,4,6,11,13,15,17,18,19,20 +p3-7|20|1.12094|0|7|1,2,3,7,9,10,11,12,13,20 +p3-7|20|1.14217|0|8|3,4,5,6,7,9,10,14,16,17,20 +p3-7|20|1.20440|0|9|1,2,5,7,12,14,15,16,17,18,19,20 +p3-7|20|1.15763|0|10|3,4,7,8,10,11,12,13,15,16,17,18,19,20 +p3-7|20|1.16279|0|11|2,6,9,11,14,15,16,17,18,19,20 +p3-7|20|1.21542|0|12|1,4,6,11,13,15,17,20 +p3-7|20|1.20188|0|13|4,5,6,7,8,14,17,18,20 +p3-7|20|1.15334|0|14|1,2,4,5,14,16,17,18,19,20 +p3-7|20|1.22557|0|15|1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 +p3-7|20|1.24515|0|16|3,4,5,6,7,9,10,13,15,16,20 +p3-7|20|1.19192|0|17|1,2,3,5,8,9,10,11,12,13,15,16,17,18,19,20 +p3-7|20|1.19192|0|17|1,2,3,5,8,9,10,11,12,13,14,16,17,18,19,20 +p3-7|20|1.22136|0|18|1,2,3,5,6,7,9,11,13,15,16,18,19,20 +p3-7|20|1.15375|0|19|2,4,6,7,8,10,13 +p3-7|20|1.23523|0|20|3,4,5,8,9,10,11,16,20 +p3-7|20|1.15873|0|21|1,2,3,7,13,14,15,16,17,18,19 +p3-7|20|1.24170|0|22|1,4,5,9,10,11,12,13,16,20 +p3-7|20|1.28268|0|23|1,2,7,8,9,18,20 +p3-7|20|1.29784|0|24|2,4,5,7,8,9,10,13,16,17 +p3-7|20|1.29831|0|25|4,6,7,8,9,10,12,14,20 +p3-7|20|1.29831|0|25|3,6,7,8,9,10,12,14,20 +p3-7|20|1.34493|0|26|2,3,6,7,8,14,17,18 +p3-7|20|1.31854|0|27|1,2,5,6,8,9,10,11,13,14,17,18,19 +p3-7|20|1.21213|0|28|1,3,4,7,9,12,13,14 +p3-7|20|1.22641|0|29|1,2,3,4,6,7,9,10,11,15,16,17,18,19,20 +p3-7|20|1.33157|0|30|3,4,5,8,9,10,11,15,20 +p3-7|20|1.22996|0|31|1,3,5,7,8,9,12,16,17,18,19 +p3-7|20|1.32281|0|32|2,4,5,6,7,9,13,15,16,17,18,19 +p8-14|20|1.02738|0|1|1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 +p8-14|20|1.07560|0|2|3,4,7,9,10,12,13,14,15,17,19,20 +p8-14|20|1.07560|0|2|3,4,7,9,10,11,13,14,15,17,19,20 +p8-14|20|1.07481|0|3|1,3,4,5,6,8,9,10,13,14,18,19,20 +p8-14|20|1.10625|0|4|1,2,4,6,8,9,12,13,14,16,17,18,19,20 +p8-14|20|1.10625|0|4|1,2,4,6,8,9,11,13,14,16,17,18,19,20 +p8-14|20|1.12535|0|5|2,3,6,7,10,15,20 +p8-14|20|1.12321|0|6|3,4,5,6,8,9,10,12,13,18,19,20 +p8-14|20|1.12321|0|6|3,4,5,6,8,9,10,12,13,17,19,20 +p8-14|20|1.12321|0|6|3,4,5,6,8,9,10,11,13,18,19,20 +p8-14|20|1.12321|0|6|3,4,5,6,8,9,10,11,13,17,19,20 +p8-14|20|1.15344|0|7|1,3,7,8,12,13,18 +p8-14|20|1.15344|0|7|1,3,7,8,11,13,18 +p8-14|20|1.13589|0|8|1,3,4,6,7,9,10,12,13,14,15,16,18,20 +p8-14|20|1.13589|0|8|1,3,4,6,7,9,10,11,13,14,15,16,18,20 +p8-14|20|1.10142|0|9|3,4,5,6,7,8,12,13,15,16,19,20 +p8-14|20|1.10142|0|9|3,4,5,6,7,8,11,13,15,16,19,20 +p8-14|20|1.16123|0|10|1,2,3,9,10,12,15 +p8-14|20|1.16123|0|10|1,2,3,9,10,11,15 +p8-14|20|1.20399|0|11|1,2,5,6,7,9,10,11,12,16,18,19,20 +p8-14|20|1.16824|0|12|1,3,5,7,8,9,10,13,14,16,17,18,19 +p8-14|20|1.16412|0|13|1,5,7,9,10,11,12,13,14,15,16,17,18,19,20 +p8-14|20|1.21675|0|14|1,3,4,8,11,12,18 +p8-14|20|1.16470|0|15|2,3,4,6,12,14,19,20 +p8-14|20|1.16470|0|15|2,3,4,6,11,14,19,20 +p8-14|20|1.17824|0|16|1,2,4,6,7,9,10,11,12,14,19 +p8-14|20|1.26731|0|17|1,2,4,5,7,8,9,10,11,12,15,18,19 +p8-14|20|1.26731|0|17|1,2,3,5,7,8,9,10,11,12,15,18,19 +p8-14|20|1.22772|0|18|2,3,4,5,6,7,8,12,13,15,16,20 +p8-14|20|1.22772|0|18|2,3,4,5,6,7,8,11,13,15,16,20 +p8-14|20|1.15869|0|19|3,7,10,11,12,13,14,15,20 +p8-14|20|1.22905|0|20|2,4,10,11,12,16 +p8-14|20|1.24550|0|21|1,2,4,5,6,7,8,9,10,11,12,13,14,15,17,18,19,20 +p8-14|20|1.31938|0|22|1,3,4,5,7,9,10,13,14,17,18,20 +p8-14|20|1.27574|0|23|1,2,3,4,5,7,9,10,11,12,13,15,16,17,18,19,20 +p8-14|20|1.27208|0|24|1,3,4,5,8,13,14,16,17,18,19 +p8-14|20|1.26316|0|25|1,2,3,4,5,6,7,8,11,12,14,15,19,20 +p8-14|20|1.24512|0|26|5,8,10,12,14,15,17,18,19 +p8-14|20|1.24512|0|26|5,8,10,11,14,15,17,18,19 +p8-14|20|1.25495|0|27|3,6,7,8,10,13,15,17,20 +p8-14|20|1.24241|0|28|2,8,10,13,18 +p8-14|20|1.28830|0|29|1,2,3,4,5,6,7,8,9,11,12,13,15,16,17,18,19,20 +p8-14|20|1.25836|0|30|2,3,4,10,12,13,16 +p8-14|20|1.25836|0|30|2,3,4,10,11,13,16 +p8-14|20|1.32680|0|31|2,3,4,5,6,7,8,9,10,12,13,17 +p8-14|20|1.32680|0|31|2,3,4,5,6,7,8,9,10,11,13,17 +p8-14|20|1.37200|0|32|3,4,5,9,14,15,16,17,19 +p15-22|20|1.03321|0|1|1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 +p15-22|20|1.08294|0|2|1,4,5,6,7,8,9,10,11,14,15,16,17,18,19,20 +p15-22|20|1.11161|0|3|7,10,11,14,15,17,19,20 +p15-22|20|1.12694|0|4|1,4,7,8,9,10,11,14,17,18,19,20 +p15-22|20|1.17689|0|5|1,9,13,14,15,16,17,18,20 +p15-22|20|1.18447|0|6|4,5,6,7,10,11,14,15,16,19,20 +p15-22|20|1.16426|0|7|1,2,3,4,7,10,11,12,15,18,19,20 +p15-22|20|1.16426|0|7|1,2,3,4,7,9,11,12,15,18,19,20 +p15-22|20|1.20551|0|8|1,4,7,8,9,10,11,13,17,18,19,20 +p15-22|20|1.12313|0|9|1,2,3,4,5,6,7,13,14,15,16,17,18,19 +p15-22|20|1.22689|0|10|1,9,11,12,13,14,17,18,19 +p15-22|20|1.20322|0|11|1,3,4,5,6,7,8,9,10,11,13,14,15,16,17,20 +p15-22|20|1.20322|0|11|1,2,4,5,6,7,8,9,10,11,13,14,15,16,17,20 +p15-22|20|1.33634|0|12|1,2,3,4,5,6,7,9,11,16,19 +p15-22|20|1.33634|0|12|1,2,3,4,5,6,7,9,11,15,19 +p15-22|20|1.27214|0|13|1,4,8,9,10,11,12,14,15,16,17,19 +p15-22|20|1.20764|0|14|1,4,7,9,11,12,17,18,19,20 +p15-22|20|1.20314|0|15|2,4,6,7,10,11,12,13,14,16,18,20 +p15-22|20|1.20314|0|15|2,4,6,7,10,11,12,13,14,16,18,19 +p15-22|20|1.22649|0|16|1,4,7,8,9,10,11,13,17,18,19 +p15-22|20|1.23966|0|17|2,5,6,10,12,13,14,15,16,19,20 +p15-22|20|1.20700|0|18|1,2,3,4,7,9,10,11,12,14,15,16,18,20 +p15-22|20|1.31661|0|19|1,3,4,6,7,8,10,12,13,16,17,18,19,20 +p15-22|20|1.24893|0|20|1,3,4,5,7,8,9,15,16,18,20 +p15-22|20|1.24294|0|21|1,2,4,5,6,7,10,11,14,15,18,19,20 +p15-22|20|1.26797|0|22|8,11,13,14,15,16,17,20 +p15-22|20|1.23749|0|23|2,3,5,7,8,9,10,11,12,14,18,19,20 +p15-22|20|1.44576|0|24|1,2,3,4,5,6,7,10,11,16,19 +p15-22|20|1.44576|0|24|1,2,3,4,5,6,7,10,11,15,19 +p15-22|20|1.34316|0|25|1,2,3,4,5,9,12,13,15,16,17,18,19 +p15-22|20|1.30761|0|26|1,4,8,9,10,11,12,14,19,20 +p15-22|20|1.21623|0|27|4,5,8,9,10,11,13,15,16,18 +p15-22|20|1.29515|0|28|1,4,6,9,10,11,16,19,20 +p15-22|20|1.29515|0|28|1,4,6,9,10,11,15,19,20 +p15-22|20|1.28137|0|29|1,2,4,6,7,8,18,19,20 +p15-22|20|1.35448|0|30|1,2,4,5,8,10,11,12,14,15,16,19,20 +p15-22|20|1.35448|0|30|1,2,4,5,8,10,11,12,13,15,16,19,20 +p15-22|20|1.28629|0|31|1,4,6,10,13,14,15,17,20 +p15-22|20|1.28629|0|31|1,4,6,10,13,14,15,16,20 +p15-22|20|1.30593|0|32|1,5,7,9,12,14,18,19 +p23-26|20|1.01750|0|1|1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 +p23-26|20|1.05069|0|2|1,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20 +p23-26|20|1.07639|0|3|4,7,9,10,13,14,15,16,17,19,20 +p23-26|20|1.08017|0|4|2,3,4,5,6,7,8,9,11,13,17,20 +p23-26|20|1.09749|0|5|4,6,7,9,11,20 +p23-26|20|1.10653|0|6|1,2,4,5,8,9,10,15,18,20 +p23-26|20|1.12660|0|7|1,2,3,4,6,8,9,10,11,12,13,14,15,16,20 +p23-26|20|1.12015|0|8|4,7,8,9,11,16,19,20 +p23-26|20|1.15687|0|9|2,3,4,5,10,11,14,15,17,20 +p23-26|20|1.15687|0|9|2,3,4,5,10,11,13,15,17,20 +p23-26|20|1.15155|0|10|4,6,8,9,11,20 +p23-26|20|1.14671|0|11|2,4,10,12,13,18 +p23-26|20|1.17836|0|12|4,6,7,10,15,17,18 +p23-26|20|1.17998|0|13|3,4,5,6,7,8,13,14,15,16,17,18,19 +p23-26|20|1.27340|0|14|1,3,6,7,8,9,10,11,12,13,14,15 +p23-26|20|1.23419|0|15|2,3,4,5,7,8,11,15,17,20 +p23-26|20|1.22483|0|16|1,2,7,8,10,11,15,17,18,20 +p23-26|20|1.25740|0|17|2,6,9,10,11,12,13,14,19 +p23-26|20|1.19365|0|18|5,6,8,10,11,12,13,14,16,20 +p23-26|20|1.28342|0|19|1,2,3,6,7,8,9,10,11,12,13,14,15,16,17,18,19 +p23-26|20|1.24064|0|20|4,5,6,9,11,20 +p23-26|20|1.22244|0|21|1,2,4,5,6,7,8,9,10,11,13,14,15,16,18 +p23-26|20|1.20660|0|22|1,2,4,11,12,13,15,16,17,19 +p23-26|20|1.24165|0|23|1,2,3,4,5,6,7,8,9,13,14,15,16,18,19,20 +p23-26|20|1.26178|0|24|4,6,8,10,13,17,18,20 +p23-26|20|1.28908|0|25|1,2,3,4,5,7,9,10,11,12,15,18,20 +p23-26|20|1.37480|0|26|2,4,5,6,7,8,9,10,15,16,17,18,19 +p23-26|20|1.27444|0|27|1,2,5,7,15,19 +p23-26|20|1.37525|0|28|4,5,8,9,10,11,13,14,15,16,17,18,19,20 +p23-26|20|1.35329|0|29|1,2,7,10,11,15,20 +p23-26|20|1.33391|0|30|2,3,4,5,7,8,11,15,17,20 +p23-26|20|1.34269|0|31|1,6,7,9,10,11,12,14,16,17,18,19,20 +p23-26|20|1.34269|0|31|1,6,7,9,10,11,12,13,16,17,18,19,20 +p23-26|20|1.32161|0|32|4,9,12,14,15,16,18,20 +p23-26|20|1.32161|0|32|4,9,11,14,15,16,18,20 +p27-32|20|1.02674|0|1|1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 +p27-32|20|1.09852|0|2|1,2,3,5,7,10,11,14,17,18,19,20 +p27-32|20|1.11652|0|3|2,3,4,5,6,7,9,10,12,13,14,15,16,17,19,20 +p27-32|20|1.12887|0|4|1,3,4,8,9,11,14,15,18,19,20 +p27-32|20|1.11581|0|5|1,2,4,7,8,9,10,15,18,19 +p27-32|20|1.17275|0|6|1,2,7,8,9,11,12,13,15,16,17,18,20 +p27-32|20|1.13075|0|7|1,8,12,20 +p27-32|20|1.13789|0|8|1,2,3,4,7,8,11,14,15,16,17,18,19,20 +p27-32|20|1.22319|0|9|2,3,4,5,6,7,9,11,12,13,14,15,16,17,19,20 +p27-32|20|1.15284|0|10|1,2,3,6,7,9,11,13,16,18 +p27-32|20|1.18031|0|11|1,2,3,4,5,6,8,9,10,12,13,14,15,16,18,20 +p27-32|20|1.24226|0|12|2,3,7,8,10,13,15,17,18,19 +p27-32|20|1.43591|0|13|1,3,8,9,13,15,16,17,18,19,20 +p27-32|20|1.24169|0|14|5,6,8,12,13,14,15,16,17,18,19,20 +p27-32|20|1.28360|0|15|1,2,5,6,9,10,11,12,13,15,18,20 +p27-32|20|1.26968|0|16|1,2,8,11,12,13,15 +p27-32|20|1.25300|0|17|2,3,4,5,7,8,9,10,11,12,13,14,15,16,17,18,19 +p27-32|20|1.31212|0|18|3,7,8,11,12,13,14,15,16,17,18,19,20 +p27-32|20|1.35188|0|19|1,2,7,9,10,12,13,15,19 +p27-32|20|1.23995|0|20|3,4,5,6,7,8,9,10,11,12,14,15,17,20 +p27-32|20|1.33331|0|21|2,5,6,8,9,11,13,14,18,20 +p27-32|20|1.28236|0|22|1,2,3,4,5,6,7,9,10,12,13,14,15,16,17,18,19,20 +p27-32|20|1.34843|0|23|3,4,5,6,8,9,10,11,12,13,16,17,18,20 +p27-32|20|1.31080|0|24|1,2,4,5,7,8,14,15,16,17 +p27-32|20|1.41929|0|25|2,4,5,8,9,10,15,18,20 +p27-32|20|1.41929|0|25|2,4,5,8,9,10,15,17,20 +p27-32|20|1.49913|0|26|1,2,4,5,6,10,12,13,17,18,19,20 +p27-32|20|1.26371|0|27|2,3,4,5,6,7,10,11,12,13,14,15,16,18,19,20 +p27-32|20|1.40523|0|28|1,2,7,8,9,10,11,12,13,14,17,18,19,20 +p27-32|20|1.40523|0|28|1,2,7,8,9,10,11,12,13,14,16,18,19,20 +p27-32|20|1.35531|0|29|2,4,5,7,12,16,17,19,20 +p27-32|20|1.37564|0|30|1,2,6,8,9,11,12,13,16,17 +p27-32|20|1.42207|0|31|3,10,11,12,16,17,18,19 +p27-32|20|1.47450|0|32|2,4,5,6,7,8,9,10,11,12,13,15 +p33-39|20|1.01311|0|1|1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 +p33-39|20|1.03706|0|2|1,2,4,7,8,9,12,13,14,16,18,19,20 +p33-39|20|1.04607|0|3|1,2,7,8,9,10,11,12,13,14,15,16,17,19,20 +p33-39|20|1.05383|0|4|1,6,9,10,11,15,16,17,18,19 +p33-39|20|1.07528|0|5|1,2,5,6,9,10,11,12,13,14,15,16,20 +p33-39|20|1.05553|0|6|1,2,3,6,7,8,10,13,15,16,18,19 +p33-39|20|1.09023|0|7|1,2,3,4,6,14,16,17,18,20 +p33-39|20|1.08582|0|8|2,3,7,8,9,10,11,12,13,14,16,18,19,20 +p33-39|20|1.09219|0|9|2,3,4,5,7,10,11,13,15,18,20 +p33-39|20|1.09375|0|10|2,3,4,11,12,13,14,15,16,20 +p33-39|20|1.11703|0|11|2,3,4,6,7,10,14,17,18 +p33-39|20|1.07502|0|12|1,6,9,10,11,15,16,17,18,19 +p33-39|20|1.12352|0|13|3,5,7,10,11,12,13,14,16,19 +p33-39|20|1.09918|0|14|1,2,10,11,12,14,16,18 +p33-39|20|1.14921|0|15|1,2,12,13,14,15,16,20 +p33-39|20|1.14805|0|16|1,4,7,8,9,10,19 +p33-39|20|1.15133|0|17|5,6,7,8,9,10,15,16 +p33-39|20|1.14625|0|18|1,2,4,5,6,9,11,13,15,16,18,19,20 +p33-39|20|1.16930|0|19|3,4,5,10,14,15,16,17,18 +p33-39|20|1.14019|0|20|1,7,10,11,12,13,14,17,18 +p33-39|20|1.12186|0|21|1,2,3,10,14,15,16,18,20 +p33-39|20|1.18371|0|22|2,3,4,6,7,10,14,17,18 +p33-39|20|1.17155|0|23|3,5,7,8,9,11,12,13,14,18,19,20 +p33-39|20|1.17441|0|24|1,7,8,9,10,11,12,15,18,19,20 +p33-39|20|1.19543|0|25|1,2,3,4,6,7,8,9,10,11,15,16,20 +p33-39|20|1.15368|0|26|1,2,3,5,8,10,11,12,13,14,16,19 +p33-39|20|1.16843|0|27|1,2,3,5,6,8,11,12,15,17,18,19 +p33-39|20|1.14560|0|28|1,2,3,4,5,6,10,12,13,14,16,17,19,20 +p33-39|20|1.26516|0|29|1,2,4,5,7,8,9,11,12,14,15,16,17,18 +p33-39|20|1.18732|0|30|2,3,4,5,9,18,19,20 +p33-39|20|1.18732|0|30|1,3,4,5,9,18,19,20 +p33-39|20|1.18543|0|31|1,4,5,6,7,8,9,10,11,16,17,20 +p33-39|20|1.20787|0|32|1,2,3,7,20 +p40-53|20|1.02399|0|1|1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 +p40-53|20|1.08031|0|2|1,3,4,5,6,7,9,12,13,14,15,16,19,20 +p40-53|20|1.12599|0|3|1,2,3,4,6,7,8,9,10,12,14,15,16,17,18,19,20 +p40-53|20|1.13207|0|4|1,3,5,8,9,12,14,16,19,20 +p40-53|20|1.19210|0|5|1,2,3,4,5,6,7,8,9,10,11,12,13,15,16,17,18,19 +p40-53|20|1.16456|0|6|3,6,7,8,13,14,15,18,20 +p40-53|20|1.18063|0|7|1,5,7,8,12,13,14,16,17,19,20 +p40-53|20|1.18063|0|7|1,5,6,8,12,13,14,16,17,19,20 +p40-53|20|1.17301|0|8|1,2,3,7,9,11,14,15,19 +p40-53|20|1.17301|0|8|1,2,3,6,9,11,14,15,19 +p40-53|20|1.17827|0|9|1,2,4,7,8,14,15,16,17,18,20 +p40-53|20|1.31729|0|10|1,2,3,4,5,6,7,8,9,10,11,12,13,15,16,17,18,19 +p40-53|20|1.21193|0|11|1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 +p40-53|20|1.30736|0|12|3,5,6,8,13,14,15,18,20 +p40-53|20|1.24640|0|13|2,5,6,7,9,14,18,20 +p40-53|20|1.23326|0|14|2,3,10,12,13,18,20 +p40-53|20|1.28387|0|15|1,2,3,4,7,8,9,10,11,14,17,18,19,20 +p40-53|20|1.28621|0|16|1,2,3,6,9,10,14,15,19 +p40-53|20|1.22196|0|17|2,9,10,11,15,16,20 +p40-53|20|1.22196|0|17|2,8,10,11,15,16,20 +p40-53|20|1.29467|0|18|1,3,4,5,6,7,9,12,19,20 +p40-53|20|1.18831|0|19|1,2,4,8,17,19,20 +p40-53|20|1.40879|0|20|1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,17,18,20 +p40-53|20|1.28088|0|21|1,3,12,13,15,16,17,19 +p40-53|20|1.25541|0|22|1,2,6,16,17,18 +p40-53|20|1.40086|0|23|1,2,4,5,6,8,9,14,17,18 +p40-53|20|1.33411|0|24|3,5,6,8,13,14,15,19,20 +p40-53|20|1.33757|0|25|1,2,3,4,5,11,12,13,15,16,17,18,19 +p40-53|20|1.41701|0|26|2,4,5,7,12,14,16,20 +p40-53|20|1.36980|0|27|1,3,4,5,6,14,15,16,17,18,19 +p40-53|20|1.36471|0|28|1,5,8,10,12,13,15,17,18,19 +p40-53|20|1.28333|0|29|1,2,3,4,5,6,12,13,14,16,17 +p40-53|20|1.37635|0|30|1,2,3,4,5,8,9,10,11,14,17,18,19,20 +p40-53|20|1.35834|0|31|1,3,4,5,7,10,12,13,14,15,16,17 +p40-53|20|1.35834|0|31|1,3,4,5,6,10,12,13,14,15,16,17 +p40-53|20|1.36303|0|32|1,2,3,7,9,10,12,13,19,20 +p40-53|20|1.36303|0|32|1,2,3,6,9,10,12,13,19,20 +p54-55|6|1.03746|0|2|1,2,4,5,6 +p54-55|6|1.07281|0|3|1,3,5 +p54-55|6|1.09878|0|4|1,2,4 +p54-55|6|1.06062|0|5|4,5 +p54-55|6|1.09873|0|6|1,3,6 +p54-55|6|1.06063|0|7|1 +p54-55|6|1.24998|0|8|1,2,4 +p54-55|6|1.05182|0|9|1,3,5 +p54-55|6|1.08925|0|10|4,5,6 +p54-55|6|1.05905|0|11|5 +p54-55|6|1.12840|0|12|1,4,5 +p54-55|6|1.10142|0|13|3 +p54-55|6|1.09938|0|14|1 +p54-55|6|1.07569|0|15| +p54-55|6|1.48604|0|16|1,2,4 +p54-55|6|1.12024|0|17|1 +p54-55|6|1.16569|0|18|1,3,5 +p54-55|6|1.26284|0|19|1,2,3,4,5,6 +p54-55|6|1.09613|0|20|1,2,6 +p54-55|6|1.31823|0|21|2,3,4,5,6 +p54-55|6|1.20713|0|22|1,2,5 +p54-55|6|1.15002|0|23|2,6 +p54-55|6|1.35198|0|24|1,2,4 +p54-55|6|1.21678|0|25|3,5,6 +p54-55|6|1.25396|0|26|3 +p54-55|6|1.27912|0|27|1,3,5 +p54-55|6|1.16753|0|28| +p54-55|6|1.21212|0|29|1 +p54-55|6|1.24983|0|30|4,5,6 +p54-55|6|1.20054|0|31|2,3,4,5,6 +p54-55|6|1.20054|0|31|1,2,3,4,5,6 +p54-55|6|1.57587|0|32|2,3 +p0-2|20|1.02407|1|1|1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 +p0-2|20|1.04697|1|2|3,4,5,6,7,8,10,11,12,13,14,15,16,17,18,20 +p0-2|20|1.06981|1|3|2,4,5,6,7,8,9,11,12,13,15,16,17,18,19,20 +p0-2|20|1.09958|1|4|3,4,5,7,8,9,10,11,12,13,14,17,18,20 +p0-2|20|1.11567|1|5|1,3,4,6,7,9,10,12,13,15,19,20 +p0-2|20|1.10132|1|6|3,4,5,6,11,12,13,14,15,20 +p0-2|20|1.13492|1|7|8,9,10,12,13,15,16,17,19,20 +p0-2|20|1.17054|1|8|1,3,6,10,11,12,13,14,17,18,19 +p0-2|20|1.14420|1|9|1,2,4,5,6,7,8,9,12,13,14 +p0-2|20|1.17102|1|10|1,2,3,4,6,8,10,12,13,15 +p0-2|20|1.13132|1|11|1,2,3,4,6,7,8,14,16,17,18 +p0-2|20|1.17298|1|12|2,4,5,6,7,8,9,11,12,13,14,15,18,19 +p0-2|20|1.12382|1|13|4,6,8,9,10,11,12,13,14,15,16,17,20 +p0-2|20|1.12382|1|13|4,5,8,9,10,11,12,13,14,15,16,17,20 +p0-2|20|1.16162|1|14|1,2,3,4,5,6,7,9,12,15,16,17,19 +p0-2|20|1.11027|1|15|1,2,3,4,5,8,11,13,14,15,16,17,18,19,20 +p0-2|20|1.16261|1|16|2,4,5,6,7,8,10,11,12,14,15,16,17,20 +p0-2|20|1.14835|1|17|1,2,3,4,6,8,11,12,14,15,16,17,18,19,20 +p0-2|20|1.13921|1|18|1,8,9,11,13,15 +p0-2|20|1.11525|1|19|3,4,5,6,9,10,11,12,14,17,19 +p0-2|20|1.21673|1|20|2,4,7,8,11,12,14,15,16,18,19 +p0-2|20|1.24634|1|21|8,9,11,12,13,15,16,17,19,20 +p0-2|20|1.17596|1|22|1,5,6,12,14,16,17,18 +p0-2|20|1.18545|1|23|2,4,10,11,17,18,20 +p0-2|20|1.21885|1|24|1,3,6,10,11,12,13,14,17,18,20 +p0-2|20|1.25831|1|25|1,2,4,5,8,9,10,12,13,15,19 +p0-2|20|1.15806|1|26|1,2,3,8,12,18,20 +p0-2|20|1.16636|1|27|1,2,3,4,5,6,7,8,10,11,12,14,15 +p0-2|20|1.22692|1|28|1,2,3,8,10,12,13,14,15,16,17,19,20 +p0-2|20|1.21217|1|29|1,2,5,6,8,9,11,12,13,14,15,16,17,18,19,20 +p0-2|20|1.18605|1|30|3,4,6,7,11,13,14,18 +p0-2|20|1.18605|1|30|3,4,6,7,11,13,14,17 +p0-2|20|1.22297|1|31|1,2,3,5,6,7,10,13,15,16,17,18 +p0-2|20|1.18155|1|32|1,2,3,4,5,6,7,9,11,13,14,15,16,17,18,20 +p3-7|20|1.03121|1|1|1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 +p3-7|20|1.08830|1|2|1,2,5,8,9,10,11,12,13,16,17,18,19,20 +p3-7|20|1.08776|1|3|1,2,3,4,5,6,9,10,14,15,16,17,18,19 +p3-7|20|1.12896|1|4|1,2,5,6,7,8,9,10,13,16,17,18,19,20 +p3-7|20|1.11574|1|5|1,2,5,10,16,18 +p3-7|20|1.12661|1|6|1,2,3,4,6,7,9,10,13,16,17,18,19,20 +p3-7|20|1.09847|1|7|3,5,6,7,8,9,18 +p3-7|20|1.14314|1|8|1,2,5,6,7,8,9,12,13,16,17,18,19,20 +p3-7|20|1.14698|1|9|1,2,3,5,6,7,9,10,12,13,14,16,17,18,19,20 +p3-7|20|1.15070|1|10|2,3,7,11,16,18,20 +p3-7|20|1.17667|1|11|7,9,10,11,12,13,15,16,18,20 +p3-7|20|1.19611|1|12|1,2,3,4,5,7,9,10,13,16,17,18,19,20 +p3-7|20|1.17290|1|13|2,4,5,6,12,15,16,18,20 +p3-7|20|1.13563|1|14|1,2,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 +p3-7|20|1.17231|1|15|1,2,3,4,5,6,7,10,16,18,19 +p3-7|20|1.21156|1|16|1,2,9,12,13,16,17,18,19,20 +p3-7|20|1.19136|1|17|1,2,3,4,6,7,8,9,10,11,12,16,17,19,20 +p3-7|20|1.18367|1|18|2,9,13,14,16,20 +p3-7|20|1.18471|1|19|3,6,8,10,11,12,13,14 +p3-7|20|1.24049|1|20|2,9,10,13,19,20 +p3-7|20|1.16758|1|21|4,5,6,7,8,9,10,11,12,14,15,16,17,18 +p3-7|20|1.21398|1|22|1,3,4,7,9,10,11,14,15,18,20 +p3-7|20|1.27246|1|23|2,3,5,15,16,19 +p3-7|20|1.26091|1|24|2,3,4,6,7,9,10,14,18,20 +p3-7|20|1.26091|1|24|2,3,4,5,7,9,10,14,18,20 +p3-7|20|1.23294|1|25|1,3,4,5,6,7,8,13,15,16,17,18,19,20 +p3-7|20|1.27796|1|26|1,2,5,7,10,11,12,13,14,20 +p3-7|20|1.20406|1|27|1,3,4,5,6,7,10,11,12,13,14,16,19,20 +p3-7|20|1.22499|1|28|1,2,5,6,7,8,11,12 +p3-7|20|1.18379|1|29|1,2,7,9,10,12,13,14,15,16,17,18,19,20 +p3-7|20|1.26032|1|30|1,2,3,4,5,6,7,10,11,13,15,18,19,20 +p3-7|20|1.22724|1|31|1,3,4,9,11,13,14,19,20 +p3-7|20|1.24835|1|32|1,3,4,6,7,9,13,14,16,17,18 +p8-14|20|1.03252|1|1|1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 +p8-14|20|1.07297|1|2|3,4,6,7,8,9,11,13,14,15,16,17,18,20 +p8-14|20|1.07551|1|3|3,4,5,6,7,8,9,10,11,12,13,14,16,17,18 +p8-14|20|1.09790|1|4|1,2,3,5,6,7,8,9,11,15,19,20 +p8-14|20|1.12142|1|5|1,2,5,6,7,8,9,10,11,12,14,15,17,18 +p8-14|20|1.14775|1|6|2,4,5,11,13,14,15,17,20 +p8-14|20|1.14694|1|7|3,6,9,10,11,13,14,15,16,17,18,19,20 +p8-14|20|1.12559|1|8|2,3,4,5,6,7,8,9,11,15,18,20 +p8-14|20|1.13837|1|9|1,2,4,5,6,7,8,10,20 +p8-14|20|1.17128|1|10|2,6,8,9,10,11,13,14,15,16,18,19,20 +p8-14|20|1.20029|1|11|1,2,3,4,5,7,11,13,14,15,16,17,19,20 +p8-14|20|1.19787|1|12|3,4,5,6,7,8,9,10,11,12,13,14,16,19,20 +p8-14|20|1.18796|1|13|1,2,4,5,6,7,8,9,11,12,14,15,16,18,20 +p8-14|20|1.20067|1|14|2,4,5,7,9,10,12,13,18 +p8-14|20|1.24155|1|15|2,3,6,7,8,10,11,13,16,18,19,20 +p8-14|20|1.16594|1|16|1,2,6,9,11,15,16,18,19,20 +p8-14|20|1.18870|1|17|1,2,4,6,7,10,11,12,13,15,18,19,20 +p8-14|20|1.19308|1|18|1,2,3,4,5,6,7,8,9,10,11,12,13,14,17,19 +p8-14|20|1.19308|1|18|1,2,3,4,5,6,7,8,9,10,11,12,13,14,17,18 +p8-14|20|1.17715|1|19|1,2,3,4,7,10,11,17,18,19 +p8-14|20|1.28269|1|20|2,3,5,7,8,10,11,12,18 +p8-14|20|1.22499|1|21|1,2,3,4,5,7,8,9,10,11,12,13,14,15,16,17,18,19,20 +p8-14|20|1.30611|1|22|1,2,3,4,5,6,11,13,14,15,16,17,19,20 +p8-14|20|1.21043|1|23|3,6,7,8,9,12,13,16,17,19 +p8-14|20|1.27698|1|24|2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 +p8-14|20|1.23145|1|25|1,3,5,6,7,8,9,10,11,14,15,16,17,18 +p8-14|20|1.23145|1|25|1,2,6,9,10,11,12,13,17,18,19,20 +p8-14|20|1.23295|1|26|1,7,8,9,11,12,14,15,16,18 +p8-14|20|1.22650|1|27|1,2,3,4,7,10,12,13,14,15,18,19,20 +p8-14|20|1.21820|1|28|2,4,6,9,10,11,17,18,19 +p8-14|20|1.27569|1|29|1,2,3,4,5,6,7,10,11,12,13,14,15,20 +p8-14|20|1.27992|1|30|1,4,7,13,16,19,20 +p8-14|20|1.30858|1|31|1,2,6,7,8,9,10,11,12,15,16,17,18,19 +p8-14|20|1.26822|1|32|1,2,4,5,7,18 +p15-22|20|1.02250|1|1|1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 +p15-22|20|1.04473|1|2|1,3,13,14 +p15-22|20|1.11516|1|3|3,4,5,6,7,8,11,12,16,17,18 +p15-22|20|1.10167|1|4|2,3,4,5,7,8,9,10,11,13,14,15,16,20 +p15-22|20|1.24195|1|5|1,2,3,5,7,8,15,17,18,20 +p15-22|20|1.11797|1|6|1,2,3,4,6,9,10,11,14,16,17,20 +p15-22|20|1.18108|1|7|1,2,3,5,6,7,8,9,10,11,13,14,17,18,20 +p15-22|20|1.17510|1|8|2,3,4,5,7,8,10,11,12,13,14,15,17,18 +p15-22|20|1.16920|1|9|1,2,3,6,7,8,9,11 +p15-22|20|1.26460|1|10|2,3,4,5,6,7,10,12,13,15,16,17,19,20 +p15-22|20|1.21728|1|11|2,3,4,6,7,8,12,13,14,15,16,17 +p15-22|20|1.28337|1|12|2,4,5,9,11,13,14,15,17,20 +p15-22|20|1.33354|1|13|1,2,3,4,5,8,9,11,12,13,14,16,18,20 +p15-22|20|1.33205|1|14|1,2,12,13,15,16,17 +p15-22|20|1.34391|1|15|1,6,7,10,12,13,15,17,18,19,20 +p15-22|20|1.25908|1|16|2,3,5,7,8,9,10,11,12,14,15,17,18,20 +p15-22|20|1.33054|1|17|1,6,9,12,15,16,19,20 +p15-22|20|1.29935|1|18|4,5,6,7,8,9,11 +p15-22|20|1.31299|1|19|2,3,4,5,6,9,12,14,15,16,18,19,20 +p15-22|20|1.32530|1|20|2,3,10,11,13,14,15,16,20 +p15-22|20|1.24444|1|21|2,3,5,6,7,8,9,10,11,12,14,15,16,17,18 +p15-22|20|1.31280|1|22|2,3,5,6,7,8,12,13,14,15,16,17 +p15-22|20|1.26767|1|23|2,3,4,5,9,10,12,14,16,17,18,19,20 +p15-22|20|1.41116|1|24|1,2,6,7,8,11,12,16,17,18 +p15-22|20|1.45234|1|25|1,6,8,9,10,11,12,13,14,15,17,18,20 +p15-22|20|1.42835|1|26|1,2,5,6,10,12,13,14,15,16,17,18,19 +p15-22|20|1.42835|1|26|1,2,4,6,10,12,13,14,15,16,17,18,19 +p15-22|20|1.28456|1|27|1,2,3,5,6,7,8,9,10,14,19,20 +p15-22|20|1.28456|1|27|1,2,3,4,6,7,8,9,10,14,19,20 +p15-22|20|1.42648|1|28|1,2,4,5,7,12,14,15,16,17 +p15-22|20|1.36946|1|29|1,2,3,4,5,6,7,8,9,10,11,12,16,18,19,20 +p15-22|20|1.42972|1|30|1,7,8,10,12,13,15,16,17 +p15-22|20|1.36725|1|31|8,17,18,20 +p15-22|20|1.40331|1|32|2,3,10,11,13,14,16,17,18 +p23-26|20|1.00326|1|1|1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 +p23-26|20|1.05094|1|2|2,3,5,6,7,8,10,12,14,17,20 +p23-26|20|1.07722|1|3|1,2,4,5,6,7,8,10,11,12,13,14,15,16,17,18,19,20 +p23-26|20|1.10665|1|4|2,3,7,8,10,12,13,14,15,17,20 +p23-26|20|1.14256|1|5|2,8,13,18,19 +p23-26|20|1.18571|1|6|1,2,3,5,6,7,11,13,14,15,16,17,18,19,20 +p23-26|20|1.18932|1|7|1,2,3,6,7,8,10,12,13,14,18 +p23-26|20|1.18932|1|7|1,2,3,6,7,8,9,12,13,14,18 +p23-26|20|1.17704|1|8|1,3,7,12,15,17,20 +p23-26|20|1.23051|1|9|3,4,7,9,15,16,17,19,20 +p23-26|20|1.16078|1|10|2,3,4,5,6,7,8,11,18,19 +p23-26|20|1.24131|1|11|3,5,6,7,14,15,17 +p23-26|20|1.26649|1|12|1,2,3,5,6,7,12,13,14,15,16,17,18,19,20 +p23-26|20|1.29792|1|13|4,5,8,9,11,12,13,14,15,16,17,18 +p23-26|20|1.31344|1|14|1,2,4,5,7,10,11,12,13,16 +p23-26|20|1.28790|1|15|7,12,13,16,20 +p23-26|20|1.32654|1|16|1,7,8,10,13,14,16,17,18,19 +p23-26|20|1.31892|1|17|1,3,4,6,7,8,9,10,11,12,13,14,15,19 +p23-26|20|1.23922|1|18|2,3,5,6,7,14,15,17,18,19,20 +p23-26|20|1.32548|1|19|1,3,6,7,10,11,12,13,14 +p23-26|20|1.34276|1|20|2,3,4,5,6,7,8,11,18,20 +p23-26|20|1.34276|1|20|2,3,4,5,6,7,8,11,18,19 +p23-26|20|1.23428|1|21|3,5,7,10,11,13,17,20 +p23-26|20|1.23428|1|21|3,5,7,9,11,13,17,20 +p23-26|20|1.34080|1|22|5,6,7,14,15,17 +p23-26|20|1.29857|1|23|1,3,6,7,9,10,12,13,14,15,16,17 +p23-26|20|1.27307|1|24|2,3,5,8,10,12,13,14,15,16,17,18,19,20 +p23-26|20|1.32147|1|25|3,4,5,6,9,10,11,13,16,17,18 +p23-26|20|1.32147|1|25|3,4,5,6,9,10,11,12,16,17,18 +p23-26|20|1.32147|1|25|3,4,5,6,8,10,11,13,16,17,18 +p23-26|20|1.32147|1|25|3,4,5,6,8,10,11,12,16,17,18 +p23-26|20|1.32147|1|25|3,4,5,6,8,9,11,13,16,17,18 +p23-26|20|1.32147|1|25|3,4,5,6,8,9,11,12,16,17,18 +p23-26|20|1.44305|1|26|1,6,11,12,13,17,20 +p23-26|20|1.37308|1|27|3,4,7,10,14,16,17,19,20 +p23-26|20|1.37308|1|27|3,4,7,9,15,16,17,19,20 +p23-26|20|1.37308|1|27|3,4,7,9,14,16,17,19,20 +p23-26|20|1.41699|1|28|1,2,3,4,7,8,9,10,11,16 +p23-26|20|1.45455|1|29|1,2,3,4,6,9,10,13,18,19,20 +p23-26|20|1.44549|1|30|1,2,3,5,6,7,11,13,14,15,18,20 +p23-26|20|1.39559|1|31|1,2,4,6,7,8,10,12 +p23-26|20|1.50492|1|32|7,11,12,13,15,16,17 +p27-32|20|1.03054|1|1|1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 +p27-32|20|1.09278|1|2|1,2,3,4,5,7,8,9,10,11,12,13,14,15,16,17,18,19 +p27-32|20|1.08704|1|3|1,2,3,4,5,7,8,9,10,14,15,16,17,18,20 +p27-32|20|1.10724|1|4|1,2,3,6,8,9,10,11,12,13,14,15,16,17,18,19 +p27-32|20|1.09025|1|5|1,2,3,4,5,6,8,9,10,11,13,14,15,17,20 +p27-32|20|1.15113|1|6|1,2,3,4,5,7,8,9,10,11,12,13,14,15,16,17,18,19 +p27-32|20|1.15091|1|7|2,7,11,15,16,17,18 +p27-32|20|1.09320|1|8|4,5,6,7,11,12,13,15,16,19,20 +p27-32|20|1.11984|1|9|1,2,3,4,5,6,7,14,15,17,18,19,20 +p27-32|20|1.15254|1|10|1,2,3,4,5,7,8,9,10,11,12,13,14,17,18,19 +p27-32|20|1.18100|1|11|1,2,3,5,6,7,8,11,12,15,16,17,18,19,20 +p27-32|20|1.19107|1|12|1,2,3,7,8,9,10,11,12,13,14,15,16,17,18,20 +p27-32|20|1.21747|1|13|3,4,7,8,9,10,12,14,18,19,20 +p27-32|20|1.24567|1|14|2,5,6,8,9,10,11,12,13,14,15,16,17,18,20 +p27-32|20|1.11538|1|15|1,2,3,4,5,7,8,9,10,11,12,13,14,15,16,17,18,20 +p27-32|20|1.14359|1|16|1,2,4,5,11,13,14,15,16,17,18 +p27-32|20|1.16115|1|17|1,6,9,10,11,12,13,14,15,16,18 +p27-32|20|1.18845|1|18|2,4,5,6,7,9,10,11,12,13,14,15,16,17,18,20 +p27-32|20|1.18845|1|18|2,4,5,6,7,9,10,11,12,13,14,15,16,17,18,19 +p27-32|20|1.27521|1|19|1,3,6,7,8,9,10,11,12,13,14,15,17,20 +p27-32|20|1.27521|1|19|1,3,6,7,8,9,10,11,12,13,14,15,17,19 +p27-32|20|1.21024|1|20|1,2,3,8,9,10,11,17,18,19 +p27-32|20|1.24263|1|21|1,2,9,10,12,13,19 +p27-32|20|1.20659|1|22|4,5,11,12,13,14,17,18,19,20 +p27-32|20|1.23921|1|23|1,5,9,10,11,12,14,17,18 +p27-32|20|1.24844|1|24|1,2,3,4,5,6,7,10,12,13,14,15,16,20 +p27-32|20|1.27997|1|25|2,3,4,6,9,10,11,12,13,16,19 +p27-32|20|1.29341|1|26|1,2,3,4,5,7,8,9,10,13,14,19 +p27-32|20|1.18162|1|27|4,8,11,13,14,16,17,18,19 +p27-32|20|1.28366|1|28|2,3,5,7,8,9,10,12,17 +p27-32|20|1.31955|1|29|1,2,5,6,7,8,10,12,13,14,16,17,18,19,20 +p27-32|20|1.23462|1|30|2,3,9,10,12,13,17 +p27-32|20|1.26810|1|31|1,2,8,9,10,13,14,15,18,20 +p27-32|20|1.18152|1|32|1,4,5,11,14,15,16,20 +p33-39|20|1.01381|1|1|1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 +p33-39|20|1.09557|1|2|1,2,4,5,6,7,9,10,12,15,16,17,18 +p33-39|20|1.09275|1|3|1,5,6,8,11,18,19 +p33-39|20|1.13624|1|4|1,2,6,7,8,10,12,15,16,17,18,20 +p33-39|20|1.08172|1|5|4,6,10,12,14,15,17,18,19 +p33-39|20|1.15967|1|6|4,5,6,7,11,14,18,20 +p33-39|20|1.16243|1|7|1,3,4,9,11,14,15,16 +p33-39|20|1.22648|1|8|1,2,6,7,9,10,12,15,16,17,18,20 +p33-39|20|1.18986|1|9|1,2,11,14,15,17,18,19 +p33-39|20|1.16943|1|10|1,2,3,11,12,13,15,16,17,18,19 +p33-39|20|1.17632|1|11|1,2,3,4,5,7,9,13,15,18,20 +p33-39|20|1.18370|1|12|4,5,6,7,11,12,18,20 +p33-39|20|1.14712|1|13|2,5,8,10,14,16,17,18 +p33-39|20|1.24233|1|14|1,10,11,14,15,16,17,18,20 +p33-39|20|1.17429|1|15|1,2,5,6,8,11,14,16,17,18,19 +p33-39|20|1.34554|1|16|1,2,3,5,6,8,10,13,14,15,16,18,19,20 +p33-39|20|1.28271|1|17|1,3,4,5,6,7,9,10,11,12,13,15,16,17,18,19,20 +p33-39|20|1.29844|1|18|1,2,4,5,6,7,9,14,18,20 +p33-39|20|1.27584|1|19|1,3,7,12,13,14,19 +p33-39|20|1.21043|1|20|3,4,9,10,18,20 +p33-39|20|1.25255|1|21|1,3,4,7,12,13,15,16,19 +p33-39|20|1.28908|1|22|1,2,4,5,6,10,19 +p33-39|20|1.35883|1|23|1,3,7,8,12,14,15,16,17 +p33-39|20|1.38822|1|24|4,5,6,8,9,13,18 +p33-39|20|1.30788|1|25|1,2,3,7,8,9,11,12,13,20 +p33-39|20|1.24277|1|26|1,2,3,4,6,7,9,10,11,12,13,14,16,17,19,20 +p33-39|20|1.25221|1|27|2,3,4,5,6,9,12,19,20 +p33-39|20|1.32341|1|28|1,3,10,11,12,13,14,15,16,17,19,20 +p33-39|20|1.28627|1|29|1,2,5,6,8,13,15 +p33-39|20|1.29810|1|30|1,2,3,4,6,9,14,15,16,17,19,20 +p33-39|20|1.38318|1|31|4,5,6,7,8,15,16,17,18,20 +p33-39|20|1.49183|1|32|1,2,3,7,8,9,10,14,15,16,17,18,19,20 +p40-53|20|1.02764|1|1|1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 +p40-53|20|1.08373|1|2|2,3,4,6,7,10,12,14,15,16,20 +p40-53|20|1.12215|1|3|1,2,4,6,7,8,9,10,11,12,14,18,19,20 +p40-53|20|1.10269|1|4|1,2,3,4,5,6,9,10,11,12,14,15,16,17,18,20 +p40-53|20|1.11896|1|5|2,5,6,7,9,10,11,12,14,16,17,18,20 +p40-53|20|1.16054|1|6|1,2,3,9,10,11,12,14,15,16,17,18,19 +p40-53|20|1.09604|1|7|1,2,3,4,5,6,9,10,13,17,20 +p40-53|20|1.17927|1|8|1,2,4,5,6,8,9,10,11,14,15,16,17,18,20 +p40-53|20|1.16730|1|9|1,2,3,6,10,11,12,14,18,19,20 +p40-53|20|1.18102|1|10|1,2,3,4,5,6,11,12,14,17,18,19,20 +p40-53|20|1.16857|1|11|2,5,6,7,8,9,13,14,18 +p40-53|20|1.23414|1|12|1,2,5,6,7,8,9,10,11,12,14,15,16,17,18,19,20 +p40-53|20|1.22106|1|13|1,2,3,4,5,11,12,15,16,19 +p40-53|20|1.15198|1|14|1,3,4,10,12,14,16,17,20 +p40-53|20|1.20292|1|15|1,2,3,4,13,14,15,16,17,18,20 +p40-53|20|1.26262|1|16|1,2,3,4,5,7,12,14,16,17,18,20 +p40-53|20|1.09966|1|17|1,3,4,5,6,7,8,10,11,13,14,16,17,18 +p40-53|20|1.25590|1|18|1,3,4,6,9,10,13,14,15,16,17,18,19 +p40-53|20|1.21757|1|19|2,3,4,5,6,7,9,11,12,13,15,16,17,18,19,20 +p40-53|20|1.22286|1|20|4,6,7,8,9,10,11,12,15,16,17,18,20 +p40-53|20|1.19148|1|21|4,12,14,16,18 +p40-53|20|1.29431|1|22|2,3,5,6,8,10,13,14,15,16,17,18,19 +p40-53|20|1.31605|1|23|2,6,8,13,15,19 +p40-53|20|1.40027|1|24|1,3,5,6,7,8,9,10,11,12,14,15,16,17,18,19 +p40-53|20|1.26810|1|25|1,2,3,4,11,12,14,16,17,18,20 +p40-53|20|1.34059|1|26|1,2,3,4,5,10,12,13,15,16,17,20 +p40-53|20|1.29807|1|27|2,3,5,7,8,9,10,11,12,13,14,15,16,17,19 +p40-53|20|1.20564|1|28|1,2,3,4,9,12,14,16,17,18 +p40-53|20|1.23233|1|29|1,4,6,7,14,15,16,17,18 +p40-53|20|1.27193|1|30|1,2,3,9,10,11,12,15,18,19 +p40-53|20|1.26810|1|31|1,3,6,7,8,9,10,11,17,18,19 +p40-53|20|1.38821|1|32|1,2,3,5,6,7,14,15,16,17,18,20 +p54-55|11|1.01866|1|1|1,2,3,4,5,6,7,8,9,10,11 +p54-55|11|1.07166|1|2|2,3,5,7,10,11 +p54-55|11|1.06110|1|3|1,2,6,8,9,10,11 +p54-55|11|1.11820|1|4|2,3,4,5,6,7,9,11 +p54-55|11|1.11955|1|5|2,3,6,8 +p54-55|11|1.12101|1|6|2,3,5,7,10,11 +p54-55|11|1.14227|1|7|1,2,3,4,6,7,8,10,11 +p54-55|11|1.28396|1|8|2,3,9,11 +p54-55|11|1.18356|1|9|1,2,3,4,5,6,8,9,10,11 +p54-55|11|1.11161|1|10|2,3,6,7,10,11 +p54-55|11|1.16260|1|11|1,2,5,7,8,9 +p54-55|11|1.24985|1|12|2,3,5,6,9,11 +p54-55|11|1.34757|1|13|1,2,3,4,8,11 +p54-55|11|1.24913|1|14|1,2,4,5,6,7,8,10,11 +p54-55|11|1.20700|1|15|2,5,6,7,11 +p54-55|11|1.46696|1|16|2,4,9 +p54-55|11|1.38533|1|17|1,3,4,6,7,10,11 +p54-55|11|1.22729|1|18|2,7,8,9,10,11 +p54-55|11|1.34825|1|19|2,5,7,8,9,10 +p54-55|11|1.25494|1|20|1,4,5,6,7,8 +p54-55|11|1.25494|1|20|1,4,5,6,7,8,11 +p54-55|11|1.43053|1|21|5,8,9,10,11 +p54-55|11|1.36405|1|22|1,2,5,7,8,9 +p54-55|11|1.26318|1|23|2,6,8,11 +p54-55|11|1.26318|1|23|2,6,7,11 +p54-55|11|1.46042|1|24|6,8,10,11 +p54-55|11|1.22895|1|25|1,3,5,6,7,9,10 +p54-55|11|1.43648|1|26|1,2,3,4,8,11 +p54-55|11|1.25634|1|27|3,8,11 +p54-55|11|1.25541|1|28|2,4,5,6,7,8 +p54-55|11|1.56364|1|29|1,2,3,5,6,7,8,9,10,11 +p54-55|11|1.34943|1|30|1,3,6,7 +p54-55|11|1.34943|1|30|1,2,6,7 +p54-55|11|1.34606|1|31|1,2,4,5,6,7,10 +p54-55|11|1.59601|1|32|1,2,3,10 diff --git a/lib.py b/lib.py index eda1d18..dfd0c56 100755 --- a/lib.py +++ b/lib.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 import math +AFFINE_INV = None + # yes it will report 2,3,5 as non-prime # though why add a check if it will never be tested anyway @@ -70,3 +72,34 @@ def elliptic_curve(x, a, b, r): if y is None: return None, None return y, -y % r + + +def affine_inverse(s, n=29): + def fn(s, n): + g = [n, s] + u = [1, 0] + v = [0, 1] + y = [None] + i = 1 + while g[i] != 0: + y.append(g[i - 1] // g[i]) + g.append(g[i - 1] - y[i] * g[i]) + u.append(u[i - 1] - y[i] * u[i]) + v.append(v[i - 1] - y[i] * v[i]) + i += 1 + return v[-2] % n + + global AFFINE_INV + if AFFINE_INV is None: + AFFINE_INV = [fn(x, n) for x in range(n)] + return AFFINE_INV[s] + + +def affine_decrypt(x, key, n=29): # key: (s, t) + return ((x - key[1]) * affine_inverse(key[0], n)) % n + + +# alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +# cipher = 'YDIDWYASDDJVAPJMMBIASDTJVAMD' +# indices = [affine_decrypt(alphabet.index(x), (5, 9), 26) for x in cipher] +# print(''.join(alphabet[x] for x in indices)) diff --git a/probability.py b/probability.py index d0d3eb9..e289ad3 100755 --- a/probability.py +++ b/probability.py @@ -1,117 +1,55 @@ #!/usr/bin/env python3 -import re -from RuneSolver import VigenereSolver -from RuneText import RuneText -from NGrams import NGrams -from HeuristicSearch import GuessVigenere, SearchInterrupt +from RuneSolver import VigenereSolver, AffineSolver +from HeuristicSearch import GuessVigenere, GuessAffine, SearchInterrupt +from HeuristicLib import load_indices, Probability +from InterruptDB import InterruptDB # from FailedAttempts import NGramShifter RUNES = 'ᚠᚢᚦᚩᚱᚳᚷᚹᚻᚾᛁᛄᛇᛈᛉᛋᛏᛒᛖᛗᛚᛝᛟᛞᚪᚫᚣᛡᛠ' -RCOUNT = len(RUNES) -ORG_INTERRUPT = 'ᚠ' -INV_INTERRUPT = RUNES.index(ORG_INTERRUPT) INVERT = False -if INVERT: - INV_INTERRUPT = 28 - INV_INTERRUPT -re_norune = re.compile('[^' + RUNES + ']') +MIN_SCORE = 1.4 - -def load_data(fname): - fname = 'pages/{}.txt'.format(fname) - print() - print('loading file:', fname) - with open(fname, 'r') as f: - data = RuneText(re_norune.sub('', f.read()))['index'] - if INVERT: - data = [28 - x for x in data] - return data - - -######################################### -# Probability : Count runes and simple frequency analysis -######################################### - -class Probability(object): - def __init__(self, numstream): - self.prob = [0] * RCOUNT - for r in numstream: - self.prob[r] += 1 - self.N = len(numstream) - - def IC(self): - X = sum(x * (x - 1) for x in self.prob) - return X / ((self.N * (self.N - 1)) / 29) - - def friedman(self): - return (K_p - K_r) / (self.IC() - K_r) - - def similarity(self): - probs = Probability.normalized(self.prob) - return sum((x - y) ** 2 for x, y in zip(PROB_NORM, probs)) - - @staticmethod - def normalized(int_prob): - total = sum(int_prob) - return [x / total for x in int_prob] # math.log(x / total, 10) - - @staticmethod - def IC_w_keylen(nums, keylen): - val = sum(Probability(nums[x::keylen]).IC() for x in range(keylen)) - return val / keylen +db = InterruptDB.load() +session_files = [] ######################################### # Perform heuristic search on the keylength, interrupts, and key ######################################### -def enum_keylengths(nums, fn_interrupt, fn_keyguess, kmin=1, kmax=32): - best_s = 0 - best_kl = 0 - iguess = SearchInterrupt(nums, INV_INTERRUPT) - print('interrupt:', ORG_INTERRUPT, 'count:', len(iguess.stops)) - for kl in range(kmin, kmax + 1): - score, intrpts = fn_interrupt(kl, iguess) - print('{} {:.4f}'.format(kl, score)) - key_guess = [] - for i, skips in enumerate(intrpts): - key = fn_keyguess(kl, iguess.join(skips)) - yield kl, score, i, skips, key - key_guess.append(key) - intrpts[i] = iguess.to_occurrence_index(skips) - print(' skip:', intrpts) - print(' key:', key_guess) - if score > best_s: - best_s = score - best_kl = kl - print(f'best estimate: keylength: {best_kl}, score: {best_s:.4f}') - - -def fn_break_vigenere(fname, data): +def break_cipher(fname, candidates, solver, key_fn): def fn_similarity(x): return Probability(x).similarity() - def fn_irp(kl, iguess): - def fn_IoC(x): - return Probability.IC_w_keylen(x, kl) - return iguess.sequential(fn_IoC, startAt=0, maxdepth=9) - # return iguess.genetic(fn_IoC, topDown=False, maxdepth=4) - # return fn_IoC(iguess.join()), [[]] # without interrupts - - def fn_key(kl, data): - return GuessVigenere(data).guess(kl, fn_similarity) - - slvr = VigenereSolver() - slvr.input.load(file=f'pages/{fname}.txt') + filename = f'pages/{fname}.txt' + slvr = solver() + slvr.input.load(file=filename) slvr.output.QUIET = True slvr.output.COLORS = False - slvr.INTERRUPT = ORG_INTERRUPT slvr.KEY_INVERT = INVERT - for kl, score, i, skips, key in enum_keylengths(data, fn_irp, fn_key, - kmin=1, kmax=32): - outfile = f'out/{fname}.{score:.3f}.{kl}.{i}.txt' + for irp_count, score, irp, kl, skips in candidates: + data = load_indices(filename, irp, maxinterrupt=irp_count) + if INVERT: + data = [28 - x for x in data] + iguess = SearchInterrupt(data, (28 - irp) if INVERT else irp) + print('score: {}, interrupt: {}, count: {}, solver: {}'.format( + score, RUNES[irp], len(iguess.stops), key_fn.__name__)) + testcase = iguess.join(iguess.from_occurrence_index(skips)) + + key = key_fn(testcase).guess(kl, fn_similarity) + print(' skip:', skips) + print(' key:', key) + txtname = f'{key_fn.__name__}.{score:.3f}_{fname}_{kl}.{irp}' + if INVERT: + txtname += '.inv' + while txtname in session_files: + txtname += '.' + session_files.append(txtname) + outfile = f'out/{txtname}.txt' with open(outfile, 'w') as f: f.write(f'{kl}, {score:.4f}, {key}, {skips}\n') slvr.output.file_output = outfile + slvr.INTERRUPT = RUNES[irp] slvr.INTERRUPT_POS = skips slvr.KEY_DATA = key slvr.run() @@ -121,13 +59,6 @@ def fn_break_vigenere(fname, data): # main ######################################### -PROB_INT = [0] * RCOUNT -for k, v in NGrams.load().items(): - PROB_INT[RUNES.index(k)] = v -PROB_NORM = Probability.normalized(PROB_INT) -K_r = 1 / 29 # 0.034482758620689655 -K_p = sum(x ** 2 for x in PROB_INT) # 0.06116195419412538 - for fname in [ # '0_welcome', # V8 # 'jpg107-167', # V13 @@ -143,6 +74,13 @@ for fname in [ # 'p40-53', # ??? 'p54-55', # ??? ]: - data = load_data(fname) - # NGramShifter().guess(data, RUNES[INV_INTERRUPT]) - fn_break_vigenere(fname, data) + # NGramShifter().guess(data, 'ᚠ') + print() + print(f'loading file: pages/{fname}.txt') + candidates = [x for x in db[fname] if x[1] >= MIN_SCORE] + if not candidates: + maxscore = max(x[1] for x in db[fname]) + print('No candidates. Highest score is only', maxscore) + continue + break_cipher(fname, candidates, AffineSolver, GuessAffine) + break_cipher(fname, candidates, VigenereSolver, GuessVigenere)