Skip to content

Instantly share code, notes, and snippets.

@andyreagan
Last active November 5, 2021 14:00
Show Gist options
  • Save andyreagan/211e4e229b6947bfb6c358c250294083 to your computer and use it in GitHub Desktop.
Save andyreagan/211e4e229b6947bfb6c358c250294083 to your computer and use it in GitHub Desktop.
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'
@andyreagan
Copy link
Author

A few assumptions.

  1. The secret is a string.
  2. We know the max length of the secrets.
  3. The length of the secrets can vary.
  4. Each encrypted secret should have the same length as the plain secret.

To check that the secret is longer than the key:

assert len(secret) <= len(key)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment