2
$\begingroup$

I am trying to create functions for encoding and decoding an affine cipher in Mathematica. I have written these two functions:

EncryptChar[char_, a_, b_] := 
  Module[{alphabet, position, shift, mod},
    alphabet = Alphabet[];
    position = Position[alphabet, char][[1]];
    position = position[[1]];
    shift = Mod[a*position + b, 26];
    Return[alphabet[[shift]]];];

DecryptChar[char_, a_, b_] := 
  Module[{alphabet, position, shift, mod},
    alphabet = Alphabet[];
    position = Position[alphabet, char][[1]];
    position = position[[1]];
    shift = Mod[a^-1*(position - b), 26];
    Return [alphabet[[shift]]];];

And when I try to decode char "p", I get this error:

DecryptChar["p", 3, 5]

During evaluation of In[116]:= Part::pkspec1: The expression 11/3 cannot be used as a part specification. >>

{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"}[[11/3]]

What have I done wrong?

$\endgroup$
  • 3
    $\begingroup$ Isn't the problem that a^-1 is supposed to be the modular inverse of a rather than just 1/a? Yes: replace a^-1 with PowerMod[a, -1, 26] in the definition of DecryptChar. $\endgroup$ – march Jan 27 '16 at 0:24
  • $\begingroup$ @march Woops. Just saw this after I posted. +1 $\endgroup$ – Edmund Jan 27 '16 at 2:00
  • $\begingroup$ In addition to the modulus inverse problem identified by others, shouldn't you check that a is relatively prime to the number of characters in your allowable alphabet (26 in this case)? $\endgroup$ – Michael Stern Jan 27 '16 at 14:57
5
$\begingroup$

You are using the wrong inverse in DecryptChar. You should be using the modular multiplicative inverse but you are using the multiplicative inverse.

DecryptChar[char_, a_, b_] :=
 Module[{alphabet, position, shift, mod},
  alphabet = Alphabet[];
  position = First@Flatten@Position[alphabet, char];
  shift = Mod[PowerMod[a, -1, 26] (position - b), 26];
  alphabet[[shift]]
  ]

DecryptChar["p", 3, 5]

(* "u" *)

Hope this helps.

$\endgroup$
  • $\begingroup$ @m_goldberg Ah, okay. I just zeroed in on the inverse issue. Thanks. $\endgroup$ – Edmund Jan 27 '16 at 3:22
  • $\begingroup$ DecryptChar["p", 3, 5] should not give "u" but "m". The OP's algorithm is incorrect. The correct pairings are u <--> n" and "m <--> p $\endgroup$ – m_goldberg Jan 27 '16 at 3:24
4
$\begingroup$

Edit

(Corrected error in algorithm)

You can reverse the encryption with Solve, which can handle modular equations.

With[{alphabet = Alphabet[]},
  With[{n = Length[alphabet]},
    EncryptChar[char_, a_, b_] :=
      Module[{position, shift},
        position = Position[alphabet, char][[1, 1]] - 1;
        shift = Mod[a position + b, n];
        alphabet[[shift + 1]]];
    DecryptChar[char_, a_, b_] :=
      Module[{position, shift},
        position = Position[alphabet, char][[1, 1]] - 1;
        shift = Solve[a x + b == position, x, Modulus -> n][[1, 1, 2]];
        alphabet[[shift + 1]]]]]

Confirm that the code now works:

(DecryptChar[EncryptChar[#, 3, 5], 3, 5] & /@ Alphabet[]) == Alphabet[]

True

Note: I also cleaned up your code a bit.

Update

I thought about this some more and decided that the problem would be better solved with associations (hash tables). An advantage of this approach is that the coder doesn't to worry about the indexing issues that trouble the OP's code. It is also is concise and efficient.

With[{chars = Alphabet[]},
  With[{n = Length[chars]},
    With[{
        fwdHash = AssociationThread[chars, Range[0, n - 1]],
        bkwHash = AssociationThread[Range[0, n - 1], chars]},
      encryptChar[char_, a_, b_] := bkwHash @ Mod[a fwdHash[char] + b, n];
      decryptChar[char_, a_, b_] :=
        bkwHash @ Solve[a x + b == fwdHash[char], x, Modulus -> n][[1, 1, 2]]]]]

(decryptChar[encryptChar[#, 3, 5], 3, 5] & /@ Alphabet[]) == Alphabet[]

True

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.