/**
         * generate a signature for the given message using the key we were
         * initialised with. For conventional GOST3410 the message should be a GOST3411
         * hash of the message of interest.
         *
         * @param message the message that will be verified later.
         */
        public BigInteger[] GenerateSignature(
            byte[] message)
        {
            byte[] mRev = new byte[message.Length]; // conversion is little-endian
            for (int i = 0; i != mRev.Length; i++)
            {
                mRev[i] = message[mRev.Length - 1 - i];
            }

            BigInteger e = new BigInteger(1, mRev);

            ECDomainParameters ec = key.Parameters;
            BigInteger n = ec.N;
            BigInteger d = ((ECPrivateKeyParameters)key).D;

            BigInteger r, s = null;

            ECMultiplier basePointMultiplier = CreateBasePointMultiplier();

            do // generate s
            {
                BigInteger k;
                do // generate r
                {
                    do
                    {
                        k = new BigInteger(n.BitLength, random);
                    }
                    while (k.SignValue == 0);

                    ECPoint p = basePointMultiplier.Multiply(ec.G, k).Normalize();

                    r = p.AffineXCoord.ToBigInteger().Mod(n);
                }
                while (r.SignValue == 0);

                s = (k.Multiply(e)).Add(d.Multiply(r)).Mod(n);
            }
            while (s.SignValue == 0);

            return new BigInteger[]{ r, s };
        }
        /**
        * Process a single block using the basic ElGamal algorithm.
        *
        * @param in the input array.
        * @param inOff the offset into the input buffer where the data starts.
        * @param length the length of the data to be processed.
        * @return the result of the ElGamal process.
        * @exception DataLengthException the input block is too large.
        */
        public byte[] ProcessBlock(
            byte[]	input,
            int		inOff,
            int		length)
        {
            if (key == null)
                throw new InvalidOperationException("ElGamal engine not initialised");

            int maxLength = forEncryption
                ?	(bitSize - 1 + 7) / 8
                :	GetInputBlockSize();

            if (length > maxLength)
                throw new DataLengthException("input too large for ElGamal cipher.\n");

            BigInteger p = key.Parameters.P;

            byte[] output;
            if (key is ElGamalPrivateKeyParameters) // decryption
            {
                int halfLength = length / 2;
                BigInteger gamma = new BigInteger(1, input, inOff, halfLength);
                BigInteger phi = new BigInteger(1, input, inOff + halfLength, halfLength);

                ElGamalPrivateKeyParameters priv = (ElGamalPrivateKeyParameters) key;

                // a shortcut, which generally relies on p being prime amongst other things.
                // if a problem with this shows up, check the p and g values!
                BigInteger m = gamma.ModPow(p.Subtract(BigInteger.One).Subtract(priv.X), p).Multiply(phi).Mod(p);

                output = m.ToByteArrayUnsigned();
            }
            else // encryption
            {
                BigInteger tmp = new BigInteger(1, input, inOff, length);

                if (tmp.BitLength >= p.BitLength)
                    throw new DataLengthException("input too large for ElGamal cipher.\n");

                ElGamalPublicKeyParameters pub = (ElGamalPublicKeyParameters) key;

                BigInteger pSub2 = p.Subtract(BigInteger.Two);

                // TODO In theory, a series of 'k', 'g.ModPow(k, p)' and 'y.ModPow(k, p)' can be pre-calculated
                BigInteger k;
                do
                {
                    k = new BigInteger(p.BitLength, random);
                }
                while (k.SignValue == 0 || k.CompareTo(pSub2) > 0);

                BigInteger g = key.Parameters.G;
                BigInteger gamma = g.ModPow(k, p);
                BigInteger phi = tmp.Multiply(pub.Y.ModPow(k, p)).Mod(p);

                output = new byte[this.GetOutputBlockSize()];

                // TODO Add methods to allow writing BigInteger to existing byte array?
                byte[] out1 = gamma.ToByteArrayUnsigned();
                byte[] out2 = phi.ToByteArrayUnsigned();
                out1.CopyTo(output, output.Length / 2 - out1.Length);
                out2.CopyTo(output, output.Length - out2.Length);
            }

            return output;
        }
        /**
         * return true if the value r and s represent a DSA signature for
         * the passed in message for standard DSA the message should be a
         * SHA-1 hash of the real message to be verified.
         */
        public virtual bool VerifySignature(byte[] message, BigInteger r, BigInteger s)
        {
            DsaParameters parameters = key.Parameters;
            BigInteger q = parameters.Q;
            BigInteger m = CalculateE(q, message);

            if (r.SignValue <= 0 || q.CompareTo(r) <= 0)
            {
                return false;
            }

            if (s.SignValue <= 0 || q.CompareTo(s) <= 0)
            {
                return false;
            }

            BigInteger w = s.ModInverse(q);

            BigInteger u1 = m.Multiply(w).Mod(q);
            BigInteger u2 = r.Multiply(w).Mod(q);

            BigInteger p = parameters.P;
            u1 = parameters.G.ModPow(u1, p);
            u2 = ((DsaPublicKeyParameters)key).Y.ModPow(u2, p);

            BigInteger v = u1.Multiply(u2).Mod(p).Mod(q);

            return v.Equals(r);
        }
        // 5.4 pg 29
        /**
         * return true if the value r and s represent a DSA signature for
         * the passed in message (for standard DSA the message should be
         * a SHA-1 hash of the real message to be verified).
         */
        public virtual bool VerifySignature(byte[] message, BigInteger r, BigInteger s)
        {
            BigInteger n = key.Parameters.N;

            // r and s should both in the range [1,n-1]
            if (r.SignValue < 1 || s.SignValue < 1
                || r.CompareTo(n) >= 0 || s.CompareTo(n) >= 0)
            {
                return false;
            }

            BigInteger e = CalculateE(n, message);
            BigInteger c = s.ModInverse(n);

            BigInteger u1 = e.Multiply(c).Mod(n);
            BigInteger u2 = r.Multiply(c).Mod(n);

            ECPoint G = key.Parameters.G;
            ECPoint Q = ((ECPublicKeyParameters) key).Q;

            ECPoint point = ECAlgorithms.SumOfTwoMultiplies(G, u1, Q, u2).Normalize();

            if (point.IsInfinity)
                return false;

            BigInteger v = point.AffineXCoord.ToBigInteger().Mod(n);

            return v.Equals(r);
        }
        /*
        * Blind message with the blind factor.
        */
        private BigInteger BlindMessage(
            BigInteger msg)
        {
            BigInteger blindMsg = blindingFactor;
            blindMsg = msg.Multiply(blindMsg.ModPow(key.Exponent, key.Modulus));
            blindMsg = blindMsg.Mod(key.Modulus);

            return blindMsg;
        }
        /**
         * return true if the value r and s represent a GOST3410 signature for
         * the passed in message (for standard GOST3410 the message should be
         * a GOST3411 hash of the real message to be verified).
         */
        public bool VerifySignature(
            byte[]		message,
            BigInteger	r,
            BigInteger	s)
        {
            byte[] mRev = new byte[message.Length]; // conversion is little-endian
            for (int i = 0; i != mRev.Length; i++)
            {
                mRev[i] = message[mRev.Length - 1 - i];
            }

            BigInteger e = new BigInteger(1, mRev);
            BigInteger n = key.Parameters.N;

            // r in the range [1,n-1]
            if (r.CompareTo(BigInteger.One) < 0 || r.CompareTo(n) >= 0)
            {
                return false;
            }

            // s in the range [1,n-1]
            if (s.CompareTo(BigInteger.One) < 0 || s.CompareTo(n) >= 0)
            {
                return false;
            }

            BigInteger v = e.ModInverse(n);

            BigInteger z1 = s.Multiply(v).Mod(n);
            BigInteger z2 = (n.Subtract(r)).Multiply(v).Mod(n);

            ECPoint G = key.Parameters.G; // P
            ECPoint Q = ((ECPublicKeyParameters)key).Q;

            ECPoint point = ECAlgorithms.SumOfTwoMultiplies(G, z1, Q, z2).Normalize();

            if (point.IsInfinity)
                return false;

            BigInteger R = point.AffineXCoord.ToBigInteger().Mod(n);

            return R.Equals(r);
        }