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

package org.bouncycastle.crypto.signers;

import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.math.ec.ECAlgorithms;
import org.bouncycastle.util.BigIntegers;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.KeyGenerationParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.math.ec.ECConstants;
import org.bouncycastle.crypto.DataLengthException;
import java.math.BigInteger;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.CipherParameters;
import java.security.SecureRandom;
import org.bouncycastle.crypto.params.ECKeyParameters;
import org.bouncycastle.crypto.DSAExt;

public class ECNRSigner implements DSAExt
{
    private boolean forSigning;
    private ECKeyParameters key;
    private SecureRandom random;
    
    @Override
    public void init(final boolean forSigning, CipherParameters parameters) {
        this.forSigning = forSigning;
        if (forSigning) {
            SecureRandom random = null;
            if (parameters instanceof ParametersWithRandom) {
                final ParametersWithRandom parametersWithRandom = (ParametersWithRandom)parameters;
                random = parametersWithRandom.getRandom();
                parameters = parametersWithRandom.getParameters();
            }
            this.key = (ECPrivateKeyParameters)parameters;
            this.random = CryptoServicesRegistrar.getSecureRandom(random);
        }
        else {
            this.key = (ECPublicKeyParameters)parameters;
            this.random = null;
        }
        CryptoServicesRegistrar.checkConstraints(Utils.getDefaultProperties("ECNR", this.key, forSigning));
    }
    
    @Override
    public BigInteger getOrder() {
        return this.key.getParameters().getN();
    }
    
    @Override
    public BigInteger[] generateSignature(final byte[] magnitude) {
        if (!this.forSigning) {
            throw new IllegalStateException("not initialised for signing");
        }
        final BigInteger order = this.getOrder();
        final BigInteger val = new BigInteger(1, magnitude);
        final ECPrivateKeyParameters ecPrivateKeyParameters = (ECPrivateKeyParameters)this.key;
        if (val.compareTo(order) >= 0) {
            throw new DataLengthException("input too large for ECNR key");
        }
        BigInteger mod;
        AsymmetricCipherKeyPair generateKeyPair;
        do {
            final ECKeyPairGenerator ecKeyPairGenerator = new ECKeyPairGenerator();
            ecKeyPairGenerator.init(new ECKeyGenerationParameters(ecPrivateKeyParameters.getParameters(), this.random));
            generateKeyPair = ecKeyPairGenerator.generateKeyPair();
            mod = ((ECPublicKeyParameters)generateKeyPair.getPublic()).getQ().getAffineXCoord().toBigInteger().add(val).mod(order);
        } while (mod.equals(ECConstants.ZERO));
        return new BigInteger[] { mod, ((ECPrivateKeyParameters)generateKeyPair.getPrivate()).getD().subtract(mod.multiply(ecPrivateKeyParameters.getD())).mod(order) };
    }
    
    @Override
    public boolean verifySignature(final byte[] magnitude, final BigInteger bigInteger, final BigInteger bigInteger2) {
        if (this.forSigning) {
            throw new IllegalStateException("not initialised for verifying");
        }
        final ECPublicKeyParameters ecPublicKeyParameters = (ECPublicKeyParameters)this.key;
        final BigInteger n = ecPublicKeyParameters.getParameters().getN();
        final int bitLength = n.bitLength();
        final BigInteger bigInteger3 = new BigInteger(1, magnitude);
        if (bigInteger3.bitLength() > bitLength) {
            throw new DataLengthException("input too large for ECNR key.");
        }
        final BigInteger t = this.extractT(ecPublicKeyParameters, bigInteger, bigInteger2);
        return t != null && t.equals(bigInteger3.mod(n));
    }
    
    public byte[] getRecoveredMessage(final BigInteger bigInteger, final BigInteger bigInteger2) {
        if (this.forSigning) {
            throw new IllegalStateException("not initialised for verifying/recovery");
        }
        final BigInteger t = this.extractT((ECPublicKeyParameters)this.key, bigInteger, bigInteger2);
        if (t != null) {
            return BigIntegers.asUnsignedByteArray(t);
        }
        return null;
    }
    
    private BigInteger extractT(final ECPublicKeyParameters ecPublicKeyParameters, final BigInteger bigInteger, final BigInteger bigInteger2) {
        final BigInteger n = ecPublicKeyParameters.getParameters().getN();
        if (bigInteger.compareTo(ECConstants.ONE) < 0 || bigInteger.compareTo(n) >= 0) {
            return null;
        }
        if (bigInteger2.compareTo(ECConstants.ZERO) < 0 || bigInteger2.compareTo(n) >= 0) {
            return null;
        }
        final ECPoint normalize = ECAlgorithms.sumOfTwoMultiplies(ecPublicKeyParameters.getParameters().getG(), bigInteger2, ecPublicKeyParameters.getQ(), bigInteger).normalize();
        if (normalize.isInfinity()) {
            return null;
        }
        return bigInteger.subtract(normalize.getAffineXCoord().toBigInteger()).mod(n);
    }
}
