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

package org.bouncycastle.crypto.agreement;

import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.math.ec.ECAlgorithms;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.params.ECKeyParameters;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.crypto.params.ParametersWithUKM;
import org.bouncycastle.crypto.CipherParameters;
import java.math.BigInteger;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.Digest;

public class ECVKOAgreement
{
    private final Digest digest;
    private ECPrivateKeyParameters key;
    private BigInteger ukm;
    
    public ECVKOAgreement(final Digest digest) {
        this.digest = digest;
    }
    
    public void init(final CipherParameters cipherParameters) {
        final ParametersWithUKM parametersWithUKM = (ParametersWithUKM)cipherParameters;
        this.key = (ECPrivateKeyParameters)parametersWithUKM.getParameters();
        this.ukm = new BigInteger(1, Arrays.reverse(parametersWithUKM.getUKM()));
        CryptoServicesRegistrar.checkConstraints(Utils.getDefaultProperties("ECVKO", this.key));
    }
    
    public int getAgreementSize() {
        return this.digest.getDigestSize();
    }
    
    @Deprecated
    public int getFieldSize() {
        return this.key.getParameters().getCurve().getFieldElementEncodingLength();
    }
    
    public byte[] calculateAgreement(final CipherParameters cipherParameters) {
        final ECPublicKeyParameters ecPublicKeyParameters = (ECPublicKeyParameters)cipherParameters;
        final ECDomainParameters parameters = this.key.getParameters();
        if (!parameters.equals(ecPublicKeyParameters.getParameters())) {
            throw new IllegalStateException("ECVKO public key has wrong domain parameters");
        }
        final BigInteger mod = parameters.getH().multiply(this.ukm).multiply(this.key.getD()).mod(parameters.getN());
        final ECPoint cleanPoint = ECAlgorithms.cleanPoint(parameters.getCurve(), ecPublicKeyParameters.getQ());
        if (cleanPoint.isInfinity()) {
            throw new IllegalStateException("Infinity is not a valid public key for ECVKO");
        }
        final ECPoint normalize = cleanPoint.multiply(mod).normalize();
        if (normalize.isInfinity()) {
            throw new IllegalStateException("Infinity is not a valid agreement value for ECVKO");
        }
        final byte[] encoded = normalize.getEncoded(false);
        final int length = encoded.length;
        final int n = length / 2;
        Arrays.reverseInPlace(encoded, length - n * 2, n);
        Arrays.reverseInPlace(encoded, length - n, n);
        final byte[] array = new byte[this.digest.getDigestSize()];
        this.digest.update(encoded, length - n * 2, n * 2);
        this.digest.doFinal(array, 0);
        return array;
    }
}
