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

package org.bouncycastle.pqc.crypto.rainbow;

import org.bouncycastle.util.Arrays;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.Digest;
import java.security.SecureRandom;
import org.bouncycastle.pqc.crypto.MessageSigner;

public class RainbowSigner implements MessageSigner
{
    private static final int MAXITS = 65536;
    private SecureRandom random;
    int signableDocumentLength;
    private ComputeInField cf;
    private RainbowKeyParameters key;
    private Digest hashAlgo;
    private Version version;
    
    public RainbowSigner() {
        this.cf = new ComputeInField();
    }
    
    @Override
    public void init(final boolean b, final CipherParameters cipherParameters) {
        if (b) {
            RainbowKeyParameters key;
            if (cipherParameters instanceof ParametersWithRandom) {
                final ParametersWithRandom parametersWithRandom = (ParametersWithRandom)cipherParameters;
                this.random = parametersWithRandom.getRandom();
                key = (RainbowKeyParameters)parametersWithRandom.getParameters();
            }
            else {
                key = (RainbowKeyParameters)cipherParameters;
                final SecureRandom secureRandom = CryptoServicesRegistrar.getSecureRandom();
                final byte[] bytes = new byte[key.getParameters().getLen_skseed()];
                secureRandom.nextBytes(bytes);
                this.random = new RainbowDRBG(bytes, key.getParameters().getHash_algo());
            }
            this.version = key.getParameters().getVersion();
            this.key = key;
        }
        else {
            this.key = (RainbowKeyParameters)cipherParameters;
            this.version = this.key.getParameters().getVersion();
        }
        this.signableDocumentLength = this.key.getDocLength();
        this.hashAlgo = this.key.getParameters().getHash_algo();
    }
    
    private byte[] genSignature(final byte[] array) {
        final byte[] array2 = new byte[this.hashAlgo.getDigestSize()];
        this.hashAlgo.update(array, 0, array.length);
        this.hashAlgo.doFinal(array2, 0);
        final int v1 = this.key.getParameters().getV1();
        final int o1 = this.key.getParameters().getO1();
        final int o2 = this.key.getParameters().getO2();
        final int m = this.key.getParameters().getM();
        final int n = this.key.getParameters().getN();
        final RainbowPrivateKeyParameters rainbowPrivateKeyParameters = (RainbowPrivateKeyParameters)this.key;
        this.random = new RainbowDRBG(RainbowUtil.hash(this.hashAlgo, rainbowPrivateKeyParameters.sk_seed, array2, new byte[this.hashAlgo.getDigestSize()]), rainbowPrivateKeyParameters.getParameters().getHash_algo());
        final short[] array3 = new short[v1];
        short[][] inverse = null;
        final short[] array4 = new short[o1];
        final short[] array5 = new short[o2];
        final short[] array6 = new short[o2];
        final short[][] array7 = new short[o2][o1];
        final short[][] array8 = new short[o2][o2];
        final byte[] bytes = new byte[rainbowPrivateKeyParameters.getParameters().getLen_salt()];
        final short[] array9 = new short[m];
        short[] multiplyMatrix = new short[o1];
        short[] solveEquation = null;
        int n2;
        short[][] array10;
        for (n2 = 0; inverse == null && n2 < 65536; inverse = this.cf.inverse(array10), ++n2) {
            final byte[] bytes2 = new byte[v1];
            this.random.nextBytes(bytes2);
            for (int i = 0; i < v1; ++i) {
                array3[i] = (short)(bytes2[i] & 0xFF);
            }
            array10 = new short[o1][o1];
            for (int j = 0; j < v1; ++j) {
                for (int k = 0; k < o1; ++k) {
                    for (int l = 0; l < o1; ++l) {
                        array10[k][l] = GF2Field.addElem(array10[k][l], GF2Field.multElem(rainbowPrivateKeyParameters.l1_F2[k][j][l], array3[j]));
                    }
                }
            }
        }
        for (int n3 = 0; n3 < o1; ++n3) {
            array4[n3] = this.cf.multiplyMatrix_quad(rainbowPrivateKeyParameters.l1_F1[n3], array3);
        }
        for (int n4 = 0; n4 < v1; ++n4) {
            for (int n5 = 0; n5 < o2; ++n5) {
                array5[n5] = this.cf.multiplyMatrix_quad(rainbowPrivateKeyParameters.l2_F1[n5], array3);
                for (int n6 = 0; n6 < o1; ++n6) {
                    array7[n5][n6] = GF2Field.addElem(array7[n5][n6], GF2Field.multElem(rainbowPrivateKeyParameters.l2_F2[n5][n4][n6], array3[n4]));
                }
                for (int n7 = 0; n7 < o2; ++n7) {
                    array8[n5][n7] = GF2Field.addElem(array8[n5][n7], GF2Field.multElem(rainbowPrivateKeyParameters.l2_F3[n5][n4][n7], array3[n4]));
                }
            }
        }
        final byte[] array11 = new byte[m];
        while (solveEquation == null && n2 < 65536) {
            final short[][] array12 = new short[o2][o2];
            this.random.nextBytes(bytes);
            final short[] messageRepresentative = this.makeMessageRepresentative(RainbowUtil.hash(this.hashAlgo, array2, bytes, array11));
            System.arraycopy(this.cf.addVect(Arrays.copyOf(messageRepresentative, o1), this.cf.multiplyMatrix(rainbowPrivateKeyParameters.s1, Arrays.copyOfRange(messageRepresentative, o1, m))), 0, array9, 0, o1);
            System.arraycopy(messageRepresentative, o1, array9, o1, o2);
            multiplyMatrix = this.cf.multiplyMatrix(inverse, this.cf.addVect(array4, Arrays.copyOf(array9, o1)));
            final short[] multiplyMatrix2 = this.cf.multiplyMatrix(array7, multiplyMatrix);
            for (int n8 = 0; n8 < o2; ++n8) {
                array6[n8] = this.cf.multiplyMatrix_quad(rainbowPrivateKeyParameters.l2_F5[n8], multiplyMatrix);
            }
            final short[] addVect = this.cf.addVect(this.cf.addVect(this.cf.addVect(multiplyMatrix2, array6), array5), Arrays.copyOfRange(array9, o1, m));
            for (int n9 = 0; n9 < o1; ++n9) {
                for (int n10 = 0; n10 < o2; ++n10) {
                    for (int n11 = 0; n11 < o2; ++n11) {
                        array12[n10][n11] = GF2Field.addElem(array12[n10][n11], GF2Field.multElem(rainbowPrivateKeyParameters.l2_F6[n10][n9][n11], multiplyMatrix[n9]));
                    }
                }
            }
            solveEquation = this.cf.solveEquation(this.cf.addMatrix(array12, array8), addVect);
            ++n2;
        }
        final short[] array13 = (solveEquation == null) ? new short[o2] : solveEquation;
        final short[] addVect2 = this.cf.addVect(this.cf.addVect(array3, this.cf.multiplyMatrix(rainbowPrivateKeyParameters.t1, multiplyMatrix)), this.cf.multiplyMatrix(rainbowPrivateKeyParameters.t4, array13));
        final short[] addVect3 = this.cf.addVect(multiplyMatrix, this.cf.multiplyMatrix(rainbowPrivateKeyParameters.t3, array13));
        final short[] copy = Arrays.copyOf(addVect2, n);
        System.arraycopy(addVect3, 0, copy, v1, o1);
        System.arraycopy(array13, 0, copy, o1 + v1, o2);
        if (n2 == 65536) {
            throw new IllegalStateException("unable to generate signature - LES not solvable");
        }
        return Arrays.concatenate(RainbowUtil.convertArray(copy), bytes);
    }
    
    @Override
    public byte[] generateSignature(final byte[] array) {
        return this.genSignature(array);
    }
    
    @Override
    public boolean verifySignature(final byte[] array, final byte[] array2) {
        final byte[] array3 = new byte[this.hashAlgo.getDigestSize()];
        this.hashAlgo.update(array, 0, array.length);
        this.hashAlgo.doFinal(array3, 0);
        final int m = this.key.getParameters().getM();
        final int n = this.key.getParameters().getN();
        final RainbowPublicMap rainbowPublicMap = new RainbowPublicMap(this.key.getParameters());
        final short[] messageRepresentative = this.makeMessageRepresentative(RainbowUtil.hash(this.hashAlgo, array3, Arrays.copyOfRange(array2, n, array2.length), new byte[m]));
        final short[] convertArray = RainbowUtil.convertArray(Arrays.copyOfRange(array2, 0, n));
        short[] array4 = null;
        switch (this.version) {
            case CLASSIC: {
                array4 = rainbowPublicMap.publicMap((RainbowPublicKeyParameters)this.key, convertArray);
                break;
            }
            case CIRCUMZENITHAL:
            case COMPRESSED: {
                array4 = rainbowPublicMap.publicMap_cyclic((RainbowPublicKeyParameters)this.key, convertArray);
                break;
            }
            default: {
                throw new IllegalArgumentException("No valid version. Please choose one of the following: classic, circumzenithal, compressed");
            }
        }
        return RainbowUtil.equals(messageRepresentative, array4);
    }
    
    private short[] makeMessageRepresentative(final byte[] array) {
        final short[] array2 = new short[this.signableDocumentLength];
        int n = 0;
        int i = 0;
        while (i < array.length) {
            array2[i] = (short)(array[n] & 0xFF);
            ++n;
            if (++i >= array2.length) {
                return array2;
            }
        }
        return array2;
    }
}
