Last active
November 5, 2021 14:00
-
-
Save andyreagan/211e4e229b6947bfb6c358c250294083 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import random | |
def decrypt(plain: str, key: list): | |
short_key = [y for y in key if y < len(plain)] | |
return ''.join([plain[y] for y in [z for z in sorted(range(len(plain)),key=short_key.__getitem__)]]) | |
def encrypt(plain: str, key: list): | |
''' | |
Shuffle x by the keys in key. | |
Since this is a one line solution, I'll provide an explanation. | |
The inner comp: | |
[z for z in key if z < len(plain)] | |
gets the permutation for the subset of indices up to the length of | |
the secret. | |
If we were to fill the plain secret to the length of the key by | |
appending spaces, then remove all of the spaces after it is | |
shuffled, this would have the same effect. | |
Any index in the key greater than the length of the plain secret | |
would be moving a space character in that scenario, | |
so we don't need those keys. | |
The rest, | |
[plain[y] for y in _key subset_] | |
just uses the key subset as an index on the plain secret. | |
''' | |
if len(plain) > len(key): | |
raise ValueError(f'Plain secret is too long at {len(plain)}, the key is only {len(key)}') | |
return ''.join([plain[y] for y in [z for z in key if z < len(plain)]]) | |
secret = '5180502011' | |
# check all the identity operations | |
assert secret == encrypt(secret, key=range(len(secret))) | |
assert secret == encrypt(secret, key=range(len(secret)+100)) | |
assert secret == decrypt(secret, key=range(len(secret))) | |
assert secret == decrypt(secret, key=range(len(secret)+100)) | |
# get a key | |
random.seed(42) | |
key = list(range(len(secret)+100)) | |
random.shuffle(key) # inplace | |
# run it through an actual encryption | |
assert secret != encrypt(secret, key=key) | |
assert secret == decrypt(encrypt(secret, key=key), key=key) | |
# check a known solution, reversing | |
simple_secret = ''.join(map(str, range(10))) | |
reverse_index = list(range(len(simple_secret)+100)) | |
reverse_index.reverse() | |
assert ''.join(map(str, reverse_index[-len(simple_secret):])) == encrypt(simple_secret, key=reverse_index) | |
# check swapping the first and last (the key will need to be the same length | |
secret = '12345' | |
key = [4, 1, 2, 3, 0] | |
assert encrypt(secret, key) == '52341' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
A few assumptions.
To check that the secret is longer than the key: