package org.bouncycastle.crypto.agreement;

import java.math.BigInteger;

import org.bouncycastle.crypto.BasicAgreement;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.MQVPrivateParameters;
import org.bouncycastle.crypto.params.MQVPublicParameters;
import org.bouncycastle.math.ec.ECAlgorithms;
import org.bouncycastle.math.ec.ECConstants;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.Properties;

public class ECMQVBasicAgreement
    implements BasicAgreement
{
    MQVPrivateParameters privParams;

    public void init(
        CipherParameters key)
    {
        this.privParams = (MQVPrivateParameters)key;
    }

    public int getFieldSize()
    {
        return (privParams.getStaticPrivateKey().getParameters().getCurve().getFieldSize() + 7) / 8;
    }

    public BigInteger calculateAgreement(CipherParameters pubKey)
    {
        if (Properties.isOverrideSet("org.bouncycastle.ec.disable_mqv"))
        {
            throw new IllegalStateException("ECMQV explicitly disabled");
        }

        MQVPublicParameters pubParams = (MQVPublicParameters)pubKey;

        ECPrivateKeyParameters staticPrivateKey = privParams.getStaticPrivateKey();
        ECDomainParameters parameters = staticPrivateKey.getParameters();

        if (!parameters.equals(pubParams.getStaticPublicKey().getParameters()))
        {
            throw new IllegalStateException("ECMQV public key components have wrong domain parameters");
        }

        ECPoint agreement = calculateMqvAgreement(parameters, staticPrivateKey,
            privParams.getEphemeralPrivateKey(), privParams.getEphemeralPublicKey(),
            pubParams.getStaticPublicKey(), pubParams.getEphemeralPublicKey()).normalize();

        if (agreement.isInfinity())
        {
            throw new IllegalStateException("Infinity is not a valid agreement value for MQV");
        }

        return agreement.getAffineXCoord().toBigInteger();
    }

    // The ECMQV Primitive as described in SEC-1, 3.4
    private ECPoint calculateMqvAgreement(
        ECDomainParameters      parameters,
        ECPrivateKeyParameters  d1U,
        ECPrivateKeyParameters  d2U,
        ECPublicKeyParameters   Q2U,
        ECPublicKeyParameters   Q1V,
        ECPublicKeyParameters   Q2V)
    {
        BigInteger n = parameters.getN();
        int e = (n.bitLength() + 1) / 2;
        BigInteger powE = ECConstants.ONE.shiftLeft(e);

        ECCurve curve = parameters.getCurve();

        ECPoint[] points = new ECPoint[]{
            // The Q2U public key is optional - but will be calculated for us if it wasn't present
            ECAlgorithms.importPoint(curve, Q2U.getQ()),
            ECAlgorithms.importPoint(curve, Q1V.getQ()),
            ECAlgorithms.importPoint(curve, Q2V.getQ())
        };

        curve.normalizeAll(points);

        ECPoint q2u = points[0], q1v = points[1], q2v = points[2];

        BigInteger x = q2u.getAffineXCoord().toBigInteger();
        BigInteger xBar = x.mod(powE);
        BigInteger Q2UBar = xBar.setBit(e);
        BigInteger s = d1U.getD().multiply(Q2UBar).add(d2U.getD()).mod(n);

        BigInteger xPrime = q2v.getAffineXCoord().toBigInteger();
        BigInteger xPrimeBar = xPrime.mod(powE);
        BigInteger Q2VBar = xPrimeBar.setBit(e);

        BigInteger hs = parameters.getH().multiply(s).mod(n);

        return ECAlgorithms.sumOfTwoMultiplies(
            q1v, Q2VBar.multiply(hs).mod(n), q2v, hs);
    }
}

@@ -2719,54 +2719,8 @@
 );%0A%0A
-        ECPoint%5B%5D points = new ECPoint%5B%5D%7B%0A    
     
@@ -2810,35 +2810,45 @@
 present%0A        
-   
+ECPoint q2u =
  ECAlgorithms.im
@@ -2837,38 +2837,37 @@
  = ECAlgorithms.
-import
+clean
 Point(curve, Q2U
@@ -2866,33 +2866,33 @@
 rve, Q2U.getQ())
-,
+;
 %0A            ECA
@@ -2876,35 +2876,45 @@
 etQ());%0A        
-   
+ECPoint q1v =
  ECAlgorithms.im
@@ -2903,38 +2903,37 @@
  = ECAlgorithms.
-import
+clean
 Point(curve, Q1V
@@ -2940,17 +2940,17 @@
 .getQ())
-,
+;
 %0A       
@@ -2950,19 +2950,29 @@
         
-   
+ECPoint q2v =
  ECAlgor
@@ -2977,22 +2977,21 @@
 orithms.
-import
+clean
 Point(cu
@@ -3010,123 +3010,8 @@
 Q())
-%0A        %7D;%0A%0A        curve.normalizeAll(points);%0A%0A        ECPoint q2u = points%5B0%5D, q1v = points%5B1%5D, q2v = points%5B2%5D
 ;%0A%0A 

Use cleanPoint on public keys, remove redundant normalization