Encrypt [publickey_, message_] :=
Module [{n, e, c},
   n = publickey [[1]];
   e = publickey [[2]];
   c = PowerMod [message, e, n]
];


Decrypt [privatekey_, message_] :=
   Encrypt [privatekey, message]


HasPassedMillerRabin [n_, numberOfTests_] :=
Module[{k, s, couldBePrime, numberOfPerformedTests, a, 
        rHasBeenFound, r, a2rk},
   s = 1;
   k = n - 1;
   While [EvenQ [k],
            (* n-1 = 2^s * k *)
      k = Quotient [k, 2];
      s = s + 1;
   ];
   couldBePrime = True;
   numberOfPerformedTests = 0;
   While [(numberOfPerformedTests < numberOfTests) && couldBePrime,
      a = Random [Integer,{2, n-1}];
      (* Print [a];*)
      rHasBeenFound = False; 
      r = 0;
      a2rk = PowerMod [a, k, n];
      rHasBeenFound = Or [(a2rk === 1), (a2rk === n-1)];
      r = 1;
      a2rk = PowerMod [a2rk, 2, n];
      While [Not[rHasBeenFound] && (r <= s - 1),
         (* Print [a2rk]; *)
         rHasBeenFound = (a2rk === n-1);
         r = r + 1;
         a2rk = PowerMod [a2rk, 2, n];
      ];
      couldBePrime = rHasBeenFound;
      numberOfPerformedTests = numberOfPerformedTests + 1;
   ];
   couldBePrime
];
     

IsPrime [n_] := HasPassedMillerRabin [n, 10];


GenerateDSAKey [seed_] :=
Module [{p, q, t, i, g, alpha, y, a},
   SeedRandom [seed];
   i = 0;
   (* Choose q *)
   q = Random [Integer, {2^159+1, 2^160-1}];
   While[Not [IsPrime [q]],
      q = Random [Integer, {2^159+1, 2^160-1}];
      i++;
   ];
   t = Random [Integer, {0, 8}];
   (* Choose p *)
   p = Random [Integer, {2^(511 + 64 * t) + 1 + (q - 2), 
                         2^(512 + 64 * t) - 1 - 1}];
   p = p - (Mod [p, q]) + 1;
   While[Not [IsPrime [p]],
      p = Random [Integer, {2^(511 + 64 * t) + 1 + (q - 2), 
                            2^(512 + 64 * t) - 1 - 1}];
      p = p - (Mod [p, q]) + 1;
      i++;
   ];
   alpha = 1;
   While [alpha == 1,
      g = Random [Integer, {1, p-1}];
      alpha = PowerMod [g, (p-1)/q, p];
      i++;
   ];
   a = Random [Integer, {1000, q-1}];
   y = PowerMod [alpha, a, p];
   Print [i];
   {{p,q,alpha,y}, a}
]
   
   
