Skip to content

Commit e8ea85c

Browse files
committed
Added new codec: scytale
1 parent 2cffe46 commit e8ea85c

4 files changed

Lines changed: 86 additions & 2 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ This library extends the native `codecs` library and provides some new encodings
3131
`radio` | text <-> radio words | aka NATO or radio phonetic alphabet
3232
`resistor` | text <-> resistor colors | aka resistor color codes
3333
`rot` | text <-> rot(N) ciphertext | aka Caesar cipher (N belongs to [1,25])
34+
`scytale` | text <-> scytale ciphertext | encrypts with L, the number of letters on the rod (belongs to [1,[)
3435
`shift` | text <-> shift(N) ciphertext | shift ordinals with N (belongs to [1,255])
3536
`sms` | text <-> phone keystrokes | also called T9 code ; uses "`-`" as a separator for encoding, "`-`" or "`_`" or whitespace for decoding
3637
`url` | text <-> URL encoded text | aka URL encoding

codext/crypto/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
from .atbash import *
44
from .bacon import *
55
from .barbie import *
6-
from .rotn import *
6+
from .rot import *
7+
from .scytale import *
78
from .shift import *
8-
from .xor_byte import *
9+
from .xor import *
910

codext/crypto/scytale.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# -*- coding: UTF-8 -*-
2+
"""Scytale-N Codec - scytale content encoding.
3+
4+
This codec:
5+
- en/decodes strings from str to str
6+
- en/decodes strings from bytes to bytes
7+
- decodes file content to str (read)
8+
- encodes file content from str to bytes (write)
9+
"""
10+
from math import ceil
11+
12+
from ..__common__ import *
13+
14+
15+
PADDING_CHAR = ""
16+
17+
18+
def scytale_encode(l):
19+
def encode(text, errors="strict"):
20+
s, n = "", int(ceil(len(text) / float(l)))
21+
for x in range(l):
22+
for y in range(n):
23+
try:
24+
s += text[y*l+x]
25+
except IndexError:
26+
s += PADDING_CHAR
27+
return s, len(s)
28+
return encode
29+
30+
31+
def scytale_decode(l):
32+
def decode(text, errors="strict"):
33+
s, n = "", int(ceil(len(text) / float(l)))
34+
pl = l * n - len(text)
35+
for x in range(n):
36+
for y in range(l):
37+
if y >= l-pl and x == n-1:
38+
continue
39+
s += text[y*n+x-max(0,y-(l-pl))]
40+
s = s.rstrip(PADDING_CHAR)
41+
return s, len(s)
42+
return decode
43+
44+
45+
add("scytale", scytale_encode, scytale_decode, r"(?i)scytale[-_]?([1-9]\d*)$")
46+

tests/test_scytale.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/usr/bin/env python
2+
# -*- coding: UTF-8 -*-
3+
"""Scytale-N codecs tests.
4+
5+
"""
6+
import os
7+
from unittest import TestCase
8+
9+
from codext.__common__ import *
10+
11+
12+
class TestCodecsScytale(TestCase):
13+
def test_codecs_scytale(self):
14+
STR = "this is a test"
15+
SC2 = "ti satshsi et"
16+
SC5 = "tithsei ssat "
17+
TFILE = "test-codec-scytale.txt"
18+
self.assertEqual(codecs.encode(STR, "scytale2"), SC2)
19+
self.assertEqual(codecs.encode(STR, "scytale-2"), SC2)
20+
self.assertEqual(codecs.encode(STR, "scytale_2"), SC2)
21+
self.assertEqual(codecs.encode(STR, "scytale-5"), SC5)
22+
self.assertEqual(codecs.encode(STR, "scytale_5"), SC5)
23+
self.assertEqual(codecs.decode(SC5, "scytale5"), STR)
24+
self.assertRaises(LookupError, codecs.decode, STR, "scytale0")
25+
self.assertRaises(LookupError, codecs.decode, STR, "scytale--10")
26+
self.assertRaises(LookupError, codecs.decode, STR, "scytale01")
27+
with codecs.open(TFILE, 'w', encoding="scytale-5") as f:
28+
f.write(b(STR))
29+
with open(TFILE) as f:
30+
r = f.read()
31+
self.assertEqual(SC5, r)
32+
with codecs.open(TFILE, encoding="scytale-5") as f:
33+
s = f.read()
34+
self.assertEqual(STR, ensure_str(s))
35+
os.remove(TFILE)
36+

0 commit comments

Comments
 (0)