// 
// Decompiled by Procyon v0.6.0
// 

package org.bouncycastle.crypto.agreement;

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

public class ECMQVBasicAgreement implements BasicAgreement
{
    MQVPrivateParameters privParams;
    
    @Override
    public void init(final CipherParameters cipherParameters) {
        this.privParams = (MQVPrivateParameters)cipherParameters;
        CryptoServicesRegistrar.checkConstraints(Utils.getDefaultProperties("ECMQV", this.privParams.getStaticPrivateKey()));
    }
    
    @Override
    public int getFieldSize() {
        return this.privParams.getStaticPrivateKey().getParameters().getCurve().getFieldElementEncodingLength();
    }
    
    @Override
    public BigInteger calculateAgreement(final CipherParameters cipherParameters) {
        if (Properties.isOverrideSet("org.bouncycastle.ec.disable_mqv")) {
            throw new IllegalStateException("ECMQV explicitly disabled");
        }
        final MQVPublicParameters mqvPublicParameters = (MQVPublicParameters)cipherParameters;
        final ECPrivateKeyParameters staticPrivateKey = this.privParams.getStaticPrivateKey();
        final ECDomainParameters parameters = staticPrivateKey.getParameters();
        if (!parameters.equals(mqvPublicParameters.getStaticPublicKey().getParameters())) {
            throw new IllegalStateException("ECMQV public key components have wrong domain parameters");
        }
        final ECPoint normalize = this.calculateMqvAgreement(parameters, staticPrivateKey, this.privParams.getEphemeralPrivateKey(), this.privParams.getEphemeralPublicKey(), mqvPublicParameters.getStaticPublicKey(), mqvPublicParameters.getEphemeralPublicKey()).normalize();
        if (normalize.isInfinity()) {
            throw new IllegalStateException("Infinity is not a valid agreement value for MQV");
        }
        return normalize.getAffineXCoord().toBigInteger();
    }
    
    private ECPoint calculateMqvAgreement(final ECDomainParameters ecDomainParameters, final ECPrivateKeyParameters ecPrivateKeyParameters, final ECPrivateKeyParameters ecPrivateKeyParameters2, final ECPublicKeyParameters ecPublicKeyParameters, final ECPublicKeyParameters ecPublicKeyParameters2, final ECPublicKeyParameters ecPublicKeyParameters3) {
        final BigInteger n = ecDomainParameters.getN();
        final int bit = (n.bitLength() + 1) / 2;
        final BigInteger shiftLeft = ECConstants.ONE.shiftLeft(bit);
        final ECCurve curve = ecDomainParameters.getCurve();
        final ECPoint cleanPoint = ECAlgorithms.cleanPoint(curve, ecPublicKeyParameters.getQ());
        final ECPoint cleanPoint2 = ECAlgorithms.cleanPoint(curve, ecPublicKeyParameters2.getQ());
        final ECPoint cleanPoint3 = ECAlgorithms.cleanPoint(curve, ecPublicKeyParameters3.getQ());
        final BigInteger mod = ecPrivateKeyParameters.getD().multiply(cleanPoint.getAffineXCoord().toBigInteger().mod(shiftLeft).setBit(bit)).add(ecPrivateKeyParameters2.getD()).mod(n);
        final BigInteger setBit = cleanPoint3.getAffineXCoord().toBigInteger().mod(shiftLeft).setBit(bit);
        final BigInteger mod2 = ecDomainParameters.getH().multiply(mod).mod(n);
        return ECAlgorithms.sumOfTwoMultiplies(cleanPoint2, setBit.multiply(mod2).mod(n), cleanPoint3, mod2);
    }
}
