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

package org.bouncycastle.crypto.signers;

import org.bouncycastle.crypto.params.DSAParameters;
import org.bouncycastle.util.BigIntegers;
import java.math.BigInteger;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.CipherParameters;
import java.security.SecureRandom;
import org.bouncycastle.crypto.params.DSAKeyParameters;
import org.bouncycastle.crypto.DSAExt;

public class DSASigner implements DSAExt
{
    private final DSAKCalculator kCalculator;
    private DSAKeyParameters key;
    private SecureRandom random;
    
    public DSASigner() {
        this.kCalculator = new RandomDSAKCalculator();
    }
    
    public DSASigner(final DSAKCalculator kCalculator) {
        this.kCalculator = kCalculator;
    }
    
    @Override
    public void init(final boolean b, final CipherParameters cipherParameters) {
        SecureRandom random = null;
        if (b) {
            if (cipherParameters instanceof ParametersWithRandom) {
                final ParametersWithRandom parametersWithRandom = (ParametersWithRandom)cipherParameters;
                this.key = (DSAPrivateKeyParameters)parametersWithRandom.getParameters();
                random = parametersWithRandom.getRandom();
            }
            else {
                this.key = (DSAPrivateKeyParameters)cipherParameters;
            }
        }
        else {
            this.key = (DSAPublicKeyParameters)cipherParameters;
        }
        CryptoServicesRegistrar.checkConstraints(Utils.getDefaultProperties("DSA", this.key, b));
        this.random = this.initSecureRandom(b && !this.kCalculator.isDeterministic(), random);
    }
    
    @Override
    public BigInteger getOrder() {
        return this.key.getParameters().getQ();
    }
    
    @Override
    public BigInteger[] generateSignature(final byte[] array) {
        final DSAParameters parameters = this.key.getParameters();
        final BigInteger q = parameters.getQ();
        final BigInteger calculateE = this.calculateE(q, array);
        final BigInteger x = ((DSAPrivateKeyParameters)this.key).getX();
        if (this.kCalculator.isDeterministic()) {
            this.kCalculator.init(q, x, array);
        }
        else {
            this.kCalculator.init(q, this.random);
        }
        final BigInteger nextK = this.kCalculator.nextK();
        final BigInteger mod = parameters.getG().modPow(nextK.add(this.getRandomizer(q, this.random)), parameters.getP()).mod(q);
        return new BigInteger[] { mod, BigIntegers.modOddInverse(q, nextK).multiply(calculateE.add(x.multiply(mod))).mod(q) };
    }
    
    @Override
    public boolean verifySignature(final byte[] array, final BigInteger x, final BigInteger bigInteger) {
        final DSAParameters parameters = this.key.getParameters();
        final BigInteger q = parameters.getQ();
        final BigInteger calculateE = this.calculateE(q, array);
        final BigInteger value = BigInteger.valueOf(0L);
        if (value.compareTo(x) >= 0 || q.compareTo(x) <= 0) {
            return false;
        }
        if (value.compareTo(bigInteger) >= 0 || q.compareTo(bigInteger) <= 0) {
            return false;
        }
        final BigInteger modOddInverseVar = BigIntegers.modOddInverseVar(q, bigInteger);
        final BigInteger mod = calculateE.multiply(modOddInverseVar).mod(q);
        final BigInteger mod2 = x.multiply(modOddInverseVar).mod(q);
        final BigInteger p3 = parameters.getP();
        return parameters.getG().modPow(mod, p3).multiply(((DSAPublicKeyParameters)this.key).getY().modPow(mod2, p3)).mod(p3).mod(q).equals(x);
    }
    
    private BigInteger calculateE(final BigInteger bigInteger, final byte[] magnitude) {
        if (bigInteger.bitLength() >= magnitude.length * 8) {
            return new BigInteger(1, magnitude);
        }
        final byte[] magnitude2 = new byte[bigInteger.bitLength() / 8];
        System.arraycopy(magnitude, 0, magnitude2, 0, magnitude2.length);
        return new BigInteger(1, magnitude2);
    }
    
    protected SecureRandom initSecureRandom(final boolean b, final SecureRandom secureRandom) {
        return b ? CryptoServicesRegistrar.getSecureRandom(secureRandom) : null;
    }
    
    private BigInteger getRandomizer(final BigInteger val, final SecureRandom secureRandom) {
        return BigIntegers.createRandomBigInteger(7, CryptoServicesRegistrar.getSecureRandom(secureRandom)).add(BigInteger.valueOf(128L)).multiply(val);
    }
}
