user1040864
user1040864

Reputation: 11

Descramble a message string using a permutation as a key

Help i'm trying to descramble a file using a permutation as a key,i know how to scramble it but i need to create a function to descramble it back to what it was using the same permutation key, here's the code:

def stringtoarray(S):
    A = []
    i = 0
    while i<len(S):
        A.append(S[i])
        i += 1
    return A

def arraytostring(A):
    S = ""
    for c in A:  # "for each element/value c in array A"
        S = S+c
    return S
#arraytostring
def scramble(S, P):  #Scramble string S with permutation P
    pn = len(P)  # length of permutation array
    E = (len(S) + pn - (len(S)%pn)) * [' ']  # array of chars, padded 
    i = 0
    while i< len(S):
        seg = i/pn   # segment number
        j = i % pn   # segment offset
        E[ seg*pn + P[j] ] = S[i]
        i += 1
    # while
    return arraytostring(E)
# scramble
print scramble("0123456789abcdefghij",[9, 14, 11, 19, 16, 18, 12, 6,
               7, 15, 0, 5, 17, 4, 3, 10, 2, 1, 8, 13])

# prints ahgedb78i0f26j194c53

I want to set it back to string "0123456789abcdefghij" again

Upvotes: 1

Views: 2185

Answers (3)

Acorn
Acorn

Reputation: 50557

Firstly some comments on your code.

The following is completely unnecessary:

def stringtoarray(S):
    A = []
    i = 0
    while i<len(S):
        A.append(S[i])
        i += 1
    return A

It can be achieved by simply doing list(your_string)

Also, if you want to iterate over something, you can use for .. in .. eg.

for char in some_string:
    # do something with character

Your arraytostring function is also unnecessary. The proper way to concatenate a list into a string is to use string.join()[docs]. For example, ''.join(['a', 'b', 'c']) would give you 'abc'.


This is how I would do the scramble/unscramble functions:

def scramble(s, p):
    chars = list(s)
    scrambled = ['']*len(chars)
    for char, i in zip(chars, p):
        scrambled[i] = char
    return ''.join(scrambled)

def unscramble(s, p):
    reverse_p = sorted(range(len(p)), key=p.__getitem__)
    return scramble(s, reverse_p)

s = "abcdefg"

p_key = [6, 1, 3, 0, 5, 2, 4]

print "original:", s

scrambled = scramble(s, p_key)

print "scrambled:", scrambled

print "unscrambled:", unscramble(scrambled, p_key)

Result:

original: 0123456789abcdefghij
scrambled: ahgedb78i0f26j194c53
unscrambled: 0123456789abcdefghij

Upvotes: 0

unutbu
unutbu

Reputation: 880587

You have, in a sense, already written the de-scrambler. All you have to do is feed scrambler the inverse permutation. Below, the inverse permutation is given by argsort(P) where P is the permutation.


def scramble(S, P):  #Scramble string S with permutation P
    pn = len(P)  # length of permutation array
    E = (len(S) + pn - (len(S)%pn)) * [' ']  # array of chars, padded
    for i in range(len(S)):
        seg,j = divmod(i,pn)
        E[ seg*pn + P[j] ] = S[i]
    return ''.join(E).rstrip()  

def argsort(seq):
    # http://stackoverflow.com/questions/3382352/3382369#3382369
    '''
    >>> seq=[1,3,0,4,2]
    >>> index=argsort(seq)
    [2, 0, 4, 1, 3]

    Given seq and the index, you can construct the sorted seq:
    >>> sorted_seq=[seq[x] for x in index]
    >>> assert sorted_seq == sorted(seq)

    Given the sorted seq and the index, you can reconstruct seq:
    >>> assert [sorted_seq[x] for x in argsort(index)] == seq
    '''
    return sorted(range(len(seq)), key=seq.__getitem__)


P=[9, 14, 11, 19, 16, 18, 12, 6, 7, 15, 0, 5, 17, 4, 3, 10, 2, 1, 8, 13]
text="0123456789abcdefghij"
print scramble(text,P)
# ahgedb78i0f26j194c53                    
print(scramble(scramble(text,P),argsort(P)))
# 0123456789abcdefghij                        

By the way, instead of pre-allocating enough space for E with

E = (len(S) + pn - (len(S)%pn)) * [' ']

you can generate the items in E in order by using argsort:

def scramble(S, P):  
    pn = len(P) 
    E = []
    idx = argsort(P)
    for i in range(len(S)):
        seg,j = divmod(i,pn)
        E.append(S[idx[j]+seg*pn])
    return ''.join(E)

Upvotes: 3

ESR
ESR

Reputation: 604

Easy. Compute the inverse of the permutation and apply that. There's a well-known algorithm for this; you can find it cited as Algorithm J from Donald Knuth's "The Art Of Computer Programming".

There appears to be source code here: http://binetacm.wikidot.com/algo:perminv

void inversePermutation(int perm[], int n, int inv[]) {
   for (int i=0; i<n; i++)
      inv[perm[i]]=i;
}

Upvotes: 0

Related Questions