public long Decrypt(Tuple tuple, Key.PrivateKey key)
        {
            var a = tuple.a;
            var b = tuple.b;
            var p = key.P;
            var x = key.X;

            // q = (a^x)^-1
            var q = modular_pow(a, p - 1 - x, p);
            var m = (b * q) % p;

            return m;
        }
        public void Decrypt(string sourceFileName, string targetFileName, Key.PrivateKey key)
        {
            // Fetch tuples
            tuples = ReadTuplesFromFile(sourceFileName, key);
            System.Diagnostics.Debug.WriteLine("Count Decrypt : " + tuples.Count());
            // Calculate byte length
            // byteLength is used to determine how to write to the target file
            var byteLength = getByteLength(key.P);

            // Open filewrite handle
            var bw = new BinaryWriter(File.Open(targetFileName, FileMode.Create));

            // Loop through each tuple, decrypt, and write
            long m;
            foreach (var t in tuples)
            {
                // Decrypt
                m = Decrypt(t, key);

                // Write
                // TODO if number of bytes is not power of 2
                switch (getByteLength(m))
                {
                    case 1:
                        bw.Write((byte)m);
                        break;
                    case 2:
                        bw.Write((short)m);
                        break;
                    case 4:
                        bw.Write((int)m);
                        break;
                    case 8:
                        bw.Write((long)m);
                        break;
                    case 16:
                        bw.Write((decimal)m);
                        break;
                }

                // Written.
            }

            bw.Close();
        }
        private void button1_Click(object sender, EventArgs e)
        {
            if (!validate_generate_key())
            {
                MessageBox.Show("X and G must be less than p");
                return;
            }

            // Generate Key Button
            SaveFileDialog fileBrowser = new SaveFileDialog();

            if (fileBrowser.ShowDialog() == DialogResult.OK)
            {
                string fileName = fileBrowser.FileName;
                Key key = new Key((long)key_generate_p.Value, (long)key_generate_g.Value,
                    (long)key_generate_x.Value);

                key.saveToFile(fileName);
            }
        }
        public void Encrypt(string fileName, Key.PublicKey key)
        {
            tuples.Clear();

            FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);

            // Block Message Length based on value of P in key
            int blockLength = getBitLength(key.P);
            int n_blockLength = blockLength;

            // byte to read from file
            int n_byte = 8;
            int byte_read = fs.ReadByte();

            // Message that want to be encrypt
            long message = 0;

            // Process Message
            while (byte_read >= 0)
            {

                int temp_bit = -1;

                while (byte_read >= 0 && message < key.P && n_blockLength > 0)
                {
                    if (n_byte == 0)
                    {
                        // Read next byte of file
                        byte_read = fs.ReadByte();
                        n_byte = 8;
                        if (byte_read < 0) break;
                    }

                    int bit = (byte_read >> (n_byte - 1)) % 2 == 0 ? 0 : 1;
                    message = (message << 1 )+ bit;

                    n_byte--;
                    n_blockLength--;

                }

                // if Message more than block or P
                if (message >= key.P || n_blockLength < 0)
                {
                    temp_bit = (byte_read >> (n_byte - 1)) % 2 == 0 ? 0 : 1;
                    message = message >> 1;
                }

                long k = key.P-2; // Must be random
                long a = modular_pow(key.G, k, key.P);
                long b = modular_pow(message, key.Y, k, key.P);

                Tuple t = new Tuple();
                t.a = a;
                t.b = b;

                tuples.Add(t);

                message = 0;
                n_blockLength = blockLength;

                // if only the temp_bit have any value
                if (temp_bit >= 0)
                {
                    message = message << 1 + temp_bit;
                    n_blockLength--;
                }

            }

            fs.Close();
        }
        private void saveKeysButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // Fetch ingredients for private key
                long p = Convert.ToInt64(pTextBox.Text);
                long g = Convert.ToInt64(gTextBox.Text);
                long x = Convert.ToInt64(xTextBox.Text);

                // Generate key
                Key k = new Key(p, g, x);
                ElGamalApplication.Key.PrivateKey pri = k.GeneratePrivateKey();
                ElGamalApplication.Key.PublicKey pub = k.GeneratePublicKey();

                SaveFileDialog fileBrowser = new SaveFileDialog();

                Nullable<bool> result = fileBrowser.ShowDialog();

                if (result == true)
                {
                    string fileName = fileBrowser.FileName;
                    k.saveToFile(fileName);
                }
            }
            catch (Exception ex)
            {
                ShowMessageBox("Key generation failed.");
            }
        }
        private void generatePrivateKeyButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // Fetch ingredients for private key
                long p = Convert.ToInt64(pTextBox.Text);
                long g = Convert.ToInt64(gTextBox.Text);
                long x = Convert.ToInt64(xTextBox.Text);

                // Generate key
                Key k = new Key(p, g, x);
                ElGamalApplication.Key.PrivateKey pri = k.GeneratePrivateKey();
                ElGamalApplication.Key.PublicKey pub = k.GeneratePublicKey();

                xTextBox.Text = pri.X.ToString();
                yTextBox.Text = pub.Y.ToString();
            }
            catch (Exception ex)
            {
                ShowMessageBox("Key generation failed.");
            }
        }
        public void Encrypt(string fileName, Key.PublicKey key)
        {
            tuples.Clear();

            FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);

            // Block Message Length based on value of P in key
            int blockLength = getByteLength(key.P);
            int n_blockLength = blockLength;
            System.Diagnostics.Debug.WriteLine(blockLength);

            // byte to read from file
            int byte_read = 0;

            // Message that want to be encrypt
            long message = 0;

            // Process Message
            while (byte_read >= 0)
            {

                int temp_byte = -1;

                while (byte_read >= 0 && message < key.P && n_blockLength > 0)
                {
                    byte_read = fs.ReadByte();
                    if (byte_read < 0) break;
                    message = 256 * message + byte_read;
                    n_blockLength--;
                    System.Diagnostics.Debug.WriteLine((char)byte_read);
                }

                // if Message more than block or P
                if (message >= key.P )
                {
                    temp_byte = byte_read;
                    message = message/256;
                }

                long k = 1520; // Must be random
                long a = modular_pow(key.G, k, key.P);
                long b = modular_pow(message, key.Y, k, key.P);

                Tuple t = new Tuple();
                t.a = a;
                t.b = b;

                tuples.Add(t);
                System.Diagnostics.Debug.WriteLine("process :" + (char)message + "," + message);
                //Console.WriteLine(message);

                message = 0;
                n_blockLength = blockLength;

                // if only the temp_bit have any value
                if (temp_byte >= 0)
                {
                    message = message*256 + temp_byte;
                    n_blockLength--;
                }
            }
            System.Diagnostics.Debug.WriteLine("Count Encrypt : " + tuples.Count());
            fs.Close();
        }
        public List<Tuple> ReadTuplesFromFile(string fileName, Key.PrivateKey key)
        {
            var tuples = new List<Tuple>();

            // Read text - init
            BinaryReader br = new BinaryReader(File.OpenRead(fileName));

            // Get block length
            int blockLength = getByteLength(key.P);

            int pos = 0;
            char currentChar;
            string hexString;
            while (pos < br.BaseStream.Length)
            {
                br.ReadChar(); // (
                ++pos;

                currentChar = br.ReadChar();
                ++pos;

                hexString = "";
                while (currentChar != ',')
                {
                    hexString += currentChar;
                    currentChar = br.ReadChar();
                    ++pos;
                }

                long a = long.Parse(hexString, System.Globalization.NumberStyles.HexNumber);

                currentChar = br.ReadChar();
                ++pos;

                hexString = "";
                while (currentChar != ')')
                {
                    hexString += currentChar;
                    currentChar = br.ReadChar();
                    ++pos;
                }
                long b = long.Parse(hexString, System.Globalization.NumberStyles.HexNumber);

                Tuple t = new Tuple();
                t.a = a;
                t.b = b;
                tuples.Add(t);
            }

            return tuples;
        }