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

package org.bouncycastle.crypto.signers;

import java.security.SecureRandom;
import org.bouncycastle.crypto.params.ECCSIPublicKeyParameters;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.params.ECCSIPrivateKeyParameters;
import org.bouncycastle.asn1.x9.X9ECParameters;
import java.io.ByteArrayOutputStream;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.math.ec.ECPoint;
import java.math.BigInteger;
import org.bouncycastle.crypto.Signer;

public class ECCSISigner implements Signer
{
    private final BigInteger q;
    private final ECPoint G;
    private final Digest digest;
    private BigInteger j;
    private BigInteger r;
    private ECPoint Y;
    private final ECPoint kpak;
    private final byte[] id;
    private CipherParameters param;
    private ByteArrayOutputStream stream;
    private boolean forSigning;
    private final int N;
    
    public ECCSISigner(final ECPoint kpak, final X9ECParameters x9ECParameters, final Digest digest, final byte[] id) {
        this.kpak = kpak;
        this.id = id;
        this.q = x9ECParameters.getCurve().getOrder();
        this.G = x9ECParameters.getG();
        (this.digest = digest).reset();
        this.N = x9ECParameters.getCurve().getOrder().bitLength() + 7 >> 3;
    }
    
    @Override
    public void init(final boolean forSigning, final CipherParameters param) {
        this.forSigning = forSigning;
        this.param = param;
        this.reset();
    }
    
    @Override
    public void update(final byte b) {
        if (this.forSigning) {
            this.digest.update(b);
        }
        else {
            this.stream.write(b);
        }
    }
    
    @Override
    public void update(final byte[] b, final int off, final int len) {
        if (this.forSigning) {
            this.digest.update(b, off, len);
        }
        else {
            this.stream.write(b, off, len);
        }
    }
    
    @Override
    public byte[] generateSignature() throws CryptoException, DataLengthException {
        final byte[] magnitude = new byte[this.digest.getDigestSize()];
        this.digest.doFinal(magnitude, 0);
        final ECCSIPrivateKeyParameters eccsiPrivateKeyParameters = (ECCSIPrivateKeyParameters)((ParametersWithRandom)this.param).getParameters();
        final BigInteger mod = new BigInteger(1, magnitude).add(this.r.multiply(eccsiPrivateKeyParameters.getSSK())).mod(this.q);
        if (mod.equals(BigInteger.ZERO)) {
            throw new IllegalArgumentException("Invalid j, retry");
        }
        return Arrays.concatenate(BigIntegers.asUnsignedByteArray(this.N, this.r), BigIntegers.asUnsignedByteArray(this.N, mod.modInverse(this.q).multiply(this.j).mod(this.q)), eccsiPrivateKeyParameters.getPublicKeyParameters().getPVT().getEncoded(false));
    }
    
    @Override
    public boolean verifySignature(final byte[] array) {
        final byte[] copy = Arrays.copyOf(array, this.N);
        final BigInteger bigInteger = new BigInteger(1, Arrays.copyOfRange(array, this.N, this.N << 1));
        this.r = new BigInteger(1, copy).mod(this.q);
        this.digest.update(copy, 0, this.N);
        final byte[] byteArray = this.stream.toByteArray();
        this.digest.update(byteArray, 0, byteArray.length);
        final byte[] magnitude = new byte[this.digest.getDigestSize()];
        this.digest.doFinal(magnitude, 0);
        return this.G.multiply(new BigInteger(1, magnitude).mod(this.q)).normalize().add(this.Y.multiply(this.r).normalize()).normalize().multiply(bigInteger).normalize().getAffineXCoord().toBigInteger().mod(this.q).equals(this.r.mod(this.q));
    }
    
    @Override
    public void reset() {
        this.digest.reset();
        CipherParameters cipherParameters = this.param;
        SecureRandom random = null;
        if (cipherParameters instanceof ParametersWithRandom) {
            random = ((ParametersWithRandom)cipherParameters).getRandom();
            cipherParameters = ((ParametersWithRandom)cipherParameters).getParameters();
        }
        ECPoint multiply = null;
        ECPoint ecPoint;
        if (this.forSigning) {
            final ECCSIPrivateKeyParameters eccsiPrivateKeyParameters = (ECCSIPrivateKeyParameters)cipherParameters;
            ecPoint = eccsiPrivateKeyParameters.getPublicKeyParameters().getPVT();
            this.j = BigIntegers.createRandomBigInteger(this.q.bitLength(), random);
            this.r = this.G.multiply(this.j).normalize().getAffineXCoord().toBigInteger().mod(this.q);
            multiply = this.G.multiply(eccsiPrivateKeyParameters.getSSK());
        }
        else {
            ecPoint = ((ECCSIPublicKeyParameters)cipherParameters).getPVT();
            this.stream = new ByteArrayOutputStream();
        }
        final byte[] encoded = this.G.getEncoded(false);
        this.digest.update(encoded, 0, encoded.length);
        final byte[] encoded2 = this.kpak.getEncoded(false);
        this.digest.update(encoded2, 0, encoded2.length);
        this.digest.update(this.id, 0, this.id.length);
        final byte[] encoded3 = ecPoint.getEncoded(false);
        this.digest.update(encoded3, 0, encoded3.length);
        final byte[] magnitude = new byte[this.digest.getDigestSize()];
        this.digest.doFinal(magnitude, 0);
        final BigInteger mod = new BigInteger(1, magnitude).mod(this.q);
        this.digest.update(magnitude, 0, magnitude.length);
        if (this.forSigning) {
            if (!multiply.subtract(ecPoint.multiply(mod)).normalize().equals(this.kpak)) {
                throw new IllegalArgumentException("Invalid KPAK");
            }
            final byte[] unsignedByteArray = BigIntegers.asUnsignedByteArray(this.N, this.r);
            this.digest.update(unsignedByteArray, 0, unsignedByteArray.length);
        }
        else {
            this.Y = ecPoint.multiply(mod).add(this.kpak).normalize();
        }
    }
}
