public MqvPublicParameters(
			ECPublicKeyParameters	staticPublicKey,
			ECPublicKeyParameters	ephemeralPublicKey)
		{
			this.staticPublicKey = staticPublicKey;
			this.ephemeralPublicKey = ephemeralPublicKey;
		}
        public virtual void ProcessServerCertificate(Certificate serverCertificate)
        {
            X509CertificateStructure x509Cert = serverCertificate.certs[0];
            SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;

            try
            {
                this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo);
            }
            catch (Exception)
            {
                throw new TlsFatalAlert(AlertDescription.unsupported_certificate);
            }

			if (tlsSigner == null)
			{
				try
				{
					this.ecAgreeServerPublicKey = ValidateECPublicKey((ECPublicKeyParameters)this.serverPublicKey);
				}
				catch (InvalidCastException)
				{
					throw new TlsFatalAlert(AlertDescription.certificate_unknown);
				}

				TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyAgreement);
			}
			else
			{
				if (!tlsSigner.IsValidPublicKey(this.serverPublicKey))
				{
					throw new TlsFatalAlert(AlertDescription.certificate_unknown);
				}

				TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
			}
			
			// TODO
            /*
            * Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the
            * signing algorithm for the certificate must be the same as the algorithm for the
            * certificate key."
            */
        }
		// The ECMQV Primitive as described in SEC-1, 3.4
		private static ECPoint calculateMqvAgreement(
			ECDomainParameters		parameters,
			ECPrivateKeyParameters	d1U,
			ECPrivateKeyParameters	d2U,
			ECPublicKeyParameters	Q2U,
			ECPublicKeyParameters	Q1V,
			ECPublicKeyParameters	Q2V)
		{
			BigInteger n = parameters.N;
			int e = (n.BitLength + 1) / 2;
			BigInteger powE = BigInteger.One.ShiftLeft(e);

			// The Q2U public key is optional
			ECPoint q;
			if (Q2U == null)
			{
				q = parameters.G.Multiply(d2U.D);
			}
			else
			{
				q = Q2U.Q;
			}

			BigInteger x = q.X.ToBigInteger();
			BigInteger xBar = x.Mod(powE);
			BigInteger Q2UBar = xBar.SetBit(e);
			BigInteger s = d1U.D.Multiply(Q2UBar).Mod(n).Add(d2U.D).Mod(n);

			BigInteger xPrime = Q2V.Q.X.ToBigInteger();
			BigInteger xPrimeBar = xPrime.Mod(powE);
			BigInteger Q2VBar = xPrimeBar.SetBit(e);

			BigInteger hs = parameters.H.Multiply(s).Mod(n);

			//ECPoint p = Q1V.Q.Multiply(Q2VBar).Add(Q2V.Q).Multiply(hs);
			ECPoint p = ECAlgorithms.SumOfTwoMultiplies(
				Q1V.Q, Q2VBar.Multiply(hs).Mod(n), Q2V.Q, hs);

			if (p.IsInfinity)
				throw new InvalidOperationException("Infinity is not a valid agreement value for MQV");

			return p;
		}
		protected bool Equals(
			ECPublicKeyParameters other)
		{
			return q.Equals(other.q) && base.Equals(other);
		}
		protected virtual ECPublicKeyParameters ValidateECPublicKey(ECPublicKeyParameters key)
		{
			// TODO Check RFC 4492 for validation
			return key;
		}
		protected virtual byte[] CalculateECDHBasicAgreement(ECPublicKeyParameters publicKey,
			ECPrivateKeyParameters privateKey)
		{
			ECDHBasicAgreement basicAgreement = new ECDHBasicAgreement();
			basicAgreement.Init(privateKey);
			BigInteger agreement = basicAgreement.CalculateAgreement(publicKey);
			return BigIntegers.AsUnsignedByteArray(agreement);
		}
		protected virtual byte[] ExternalizeKey(ECPublicKeyParameters keyParameters)
		{
			// TODO Add support for compressed encoding and SPF extension

			/*
			 * RFC 4492 5.7. ...an elliptic curve point in uncompressed or compressed format.
			 * Here, the format MUST conform to what the server has requested through a
			 * Supported Point Formats Extension if this extension was used, and MUST be
			 * uncompressed if this extension was not used.
			 */
			return keyParameters.Q.GetEncoded();
		}
 protected bool Equals(
     ECPublicKeyParameters other)
 {
     return(q.Equals(other.q) && base.Equals(other));
 }