fixed determination of pad/text/cipher lines by number
This commit is contained in:
parent
ca11fa5f32
commit
76437746a2
@ -1,6 +1,9 @@
|
|||||||
import random
|
import random
|
||||||
|
from itertools import izip
|
||||||
|
|
||||||
PAD_MODULO = 3
|
PAD_MODULO = 3
|
||||||
|
PADLINE_OFFSET = -2
|
||||||
|
TEXTLINE_OFFSET = -1
|
||||||
DEFAULT_PAD_WIDTH = 72
|
DEFAULT_PAD_WIDTH = 72
|
||||||
CIPHER_FLOOR = 1
|
CIPHER_FLOOR = 1
|
||||||
CIPHER_CEIL = 25
|
CIPHER_CEIL = 25
|
||||||
@ -53,35 +56,59 @@ def _as_line_chunks(chars, width=DEFAULT_PAD_WIDTH):
|
|||||||
yield ''.join(chunk)
|
yield ''.join(chunk)
|
||||||
|
|
||||||
|
|
||||||
def _padfill(text, pad):
|
def _padfill(text, padlines):
|
||||||
padlines = pad.splitlines()
|
padlines = [line.strip() for line in padlines if line.strip()]
|
||||||
textlines = _chunk_chars_into_lines(text, _get_textwidth(pad))
|
textlines = _chunk_chars_into_lines(text, _get_textwidth(padlines))
|
||||||
for lineno, padline in enumerate(padlines[:]):
|
for textline, padline in izip(textlines, padlines):
|
||||||
if _is_padline(lineno) or _is_cipherline(lineno):
|
yield padline
|
||||||
continue
|
yield textline
|
||||||
|
yield ''
|
||||||
|
|
||||||
|
|
||||||
|
def _cipherfill(padfilled_lines):
|
||||||
|
padline = textline = None
|
||||||
|
for i, line in enumerate(padfilled_lines):
|
||||||
|
if _is_padline(i):
|
||||||
|
padline = line
|
||||||
|
elif _is_textline(i):
|
||||||
|
textline = line
|
||||||
else:
|
else:
|
||||||
padlines[lineno] = textlines.pop(0) if textlines[1:] else ''
|
cipherline = \
|
||||||
return padlines
|
_get_cipherline_from_padline_and_textline(padline, textline)
|
||||||
|
padfilled_lines[i] = cipherline
|
||||||
|
|
||||||
|
return padfilled_lines
|
||||||
|
|
||||||
|
|
||||||
|
def _get_cipherline_from_padline_and_textline(padline, textline):
|
||||||
|
ret = []
|
||||||
|
for padchar, textchar in izip(padline, textline):
|
||||||
|
idx = (_AS_NUMS[padchar] + _AS_NUMS[textchar]) % CIPHER_CEIL
|
||||||
|
ret.append(_AS_ALPHA[idx])
|
||||||
|
return ''.join(ret)
|
||||||
|
|
||||||
|
|
||||||
def _get_textwidth(text):
|
def _get_textwidth(text):
|
||||||
return max([len(line) for line in text.splitlines()])
|
if isinstance(text, basestring):
|
||||||
|
text = text.splitlines()
|
||||||
|
return max([len(line) for line in text])
|
||||||
|
|
||||||
|
|
||||||
def _is_padline(lineno):
|
def _is_padline(lineno):
|
||||||
return not lineno % PAD_MODULO
|
return _is_cipherline(lineno + abs(PADLINE_OFFSET))
|
||||||
|
|
||||||
|
|
||||||
def _is_txtline(lineno):
|
def _is_textline(lineno):
|
||||||
return (lineno % 2 and not lineno % PAD_MODULO)
|
return _is_cipherline(lineno + abs(TEXTLINE_OFFSET))
|
||||||
|
|
||||||
|
|
||||||
def _is_cipherline(lineno):
|
def _is_cipherline(lineno):
|
||||||
return lineno % PAD_MODULO
|
return not lineno % PAD_MODULO
|
||||||
|
|
||||||
|
|
||||||
def _mk_as_alpha():
|
def _mk_as_alpha_as_nums():
|
||||||
as_alpha = dict()
|
as_alpha = {}
|
||||||
|
as_nums = {}
|
||||||
a_chr = ord('A')
|
a_chr = ord('A')
|
||||||
past_j = False
|
past_j = False
|
||||||
|
|
||||||
@ -92,7 +119,11 @@ def _mk_as_alpha():
|
|||||||
as_alpha[key] = letter
|
as_alpha[key] = letter
|
||||||
else:
|
else:
|
||||||
past_j = True
|
past_j = True
|
||||||
return as_alpha
|
|
||||||
|
for key, val in as_alpha.iteritems():
|
||||||
|
as_nums[val] = key
|
||||||
|
|
||||||
|
return as_alpha, as_nums
|
||||||
|
|
||||||
|
|
||||||
_AS_ALPHA = _mk_as_alpha()
|
_AS_ALPHA, _AS_NUMS = _mk_as_alpha_as_nums()
|
||||||
|
@ -23,40 +23,43 @@ class TestOneTimePad(unittest.TestCase):
|
|||||||
'{1}, actual={2}'.format(self._padsize,
|
'{1}, actual={2}'.format(self._padsize,
|
||||||
width, actual))
|
width, actual))
|
||||||
|
|
||||||
def test_two_out_of_every_three_lines_are_empty_on_new_pad(self):
|
def test_is_padline(self):
|
||||||
pad = OT.create_pad_lines(2000)
|
for lineno in PADLINES:
|
||||||
for lineno, line in enumerate(pad):
|
self.assertTrue(OT._is_padline(lineno),
|
||||||
line = line.strip()
|
'line {0} is padline'.format(lineno))
|
||||||
if OT._is_padline(lineno):
|
for lineno in TEXTLINES:
|
||||||
self.assertTrue(bool(len(line)),
|
self.assertFalse(OT._is_padline(lineno),
|
||||||
'pad line {0} is non-empty'.format(lineno))
|
'line {0} is not padline'.format(lineno))
|
||||||
elif OT._is_txtline(lineno):
|
for lineno in CIPHERLINES:
|
||||||
self.assertFalse(bool(len(line)),
|
self.assertFalse(OT._is_padline(lineno),
|
||||||
'text line {0} is empty'.format(lineno))
|
'line {0} is not padline'.format(lineno))
|
||||||
elif OT._is_cipherline(lineno):
|
|
||||||
self.assertFalse(bool(len(line)),
|
|
||||||
'cipher line {0} is empty'.format(lineno))
|
|
||||||
else:
|
|
||||||
raise NotImplementedError(lineno)
|
|
||||||
|
|
||||||
def test_padfill_leaves_every_third_line_empty(self):
|
def test_is_textline(self):
|
||||||
msg = self.msg[:]
|
for lineno in TEXTLINES:
|
||||||
pad = OT.create_pad(len(msg))
|
self.assertTrue(OT._is_textline(lineno),
|
||||||
filled = OT._padfill(msg, pad)
|
'line {0} is textline'.format(lineno))
|
||||||
self.assertTrue(bool(filled))
|
for lineno in PADLINES:
|
||||||
for lineno, line in enumerate(filled):
|
self.assertFalse(OT._is_textline(lineno),
|
||||||
line = line.strip()
|
'line {0} is not textline'.format(lineno))
|
||||||
if OT._is_cipherline(lineno):
|
for lineno in CIPHERLINES:
|
||||||
self.assertFalse(bool(len(line)),
|
self.assertFalse(OT._is_textline(lineno),
|
||||||
'line {0} is empty'.format(lineno))
|
'line {0} is not textline'.format(lineno))
|
||||||
elif OT._is_txtline(lineno):
|
|
||||||
self.assertTrue(bool(len(line)),
|
def test_is_cipherline(self):
|
||||||
'text line {0} is non-empty'.format(lineno))
|
for lineno in CIPHERLINES:
|
||||||
elif OT._is_padline(lineno):
|
self.assertTrue(OT._is_cipherline(lineno),
|
||||||
self.assertTrue(bool(len(line)),
|
'line {0} is cipherline'.format(lineno))
|
||||||
'pad line {0} is non-empty'.format(lineno))
|
for lineno in PADLINES:
|
||||||
else:
|
self.assertFalse(OT._is_cipherline(lineno),
|
||||||
raise NotImplementedError(lineno)
|
'line {0} is not cipherline'.format(lineno))
|
||||||
|
for lineno in TEXTLINES:
|
||||||
|
self.assertFalse(OT._is_cipherline(lineno),
|
||||||
|
'line {0} is not cipherline'.format(lineno))
|
||||||
|
|
||||||
|
|
||||||
|
PADLINES = (1, 4, 7, 10, 13, 16, 19, 22, 25)
|
||||||
|
TEXTLINES = (2, 5, 8, 11, 14, 17, 20, 23, 26)
|
||||||
|
CIPHERLINES = (3, 6, 9, 12, 15, 18, 21, 24, 27)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
Loading…
x
Reference in New Issue
Block a user