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

package org.bouncycastle.pqc.crypto.falcon;

import org.bouncycastle.util.Arrays;
import org.bouncycastle.crypto.digests.SHAKEDigest;
import java.security.SecureRandom;

class FalconNIST
{
    final int NONCELEN;
    final int LOGN;
    private final int N;
    private final SecureRandom rand;
    private final int CRYPTO_SECRETKEYBYTES;
    private final int CRYPTO_PUBLICKEYBYTES;
    final int CRYPTO_BYTES;
    
    FalconNIST(final int logn, final int noncelen, final SecureRandom rand) {
        this.rand = rand;
        this.LOGN = logn;
        this.NONCELEN = noncelen;
        this.N = 1 << logn;
        this.CRYPTO_PUBLICKEYBYTES = 1 + 14 * this.N / 8;
        if (logn == 10) {
            this.CRYPTO_SECRETKEYBYTES = 2305;
            this.CRYPTO_BYTES = 1330;
        }
        else if (logn == 9 || logn == 8) {
            this.CRYPTO_SECRETKEYBYTES = 1 + 6 * this.N * 2 / 8 + this.N;
            this.CRYPTO_BYTES = 690;
        }
        else if (logn == 7 || logn == 6) {
            this.CRYPTO_SECRETKEYBYTES = 1 + 7 * this.N * 2 / 8 + this.N;
            this.CRYPTO_BYTES = 690;
        }
        else {
            this.CRYPTO_SECRETKEYBYTES = 1 + this.N * 2 + this.N;
            this.CRYPTO_BYTES = 690;
        }
    }
    
    byte[][] crypto_sign_keypair(final byte[] array, final byte[] array2) {
        final byte[] array3 = new byte[this.N];
        final byte[] array4 = new byte[this.N];
        final byte[] array5 = new byte[this.N];
        final short[] array6 = new short[this.N];
        final byte[] bytes = new byte[48];
        final SHAKEDigest shakeDigest = new SHAKEDigest(256);
        this.rand.nextBytes(bytes);
        shakeDigest.update(bytes, 0, bytes.length);
        FalconKeyGen.keygen(shakeDigest, array3, array4, array5, array6, this.LOGN);
        array2[0] = (byte)(80 + this.LOGN);
        final int n = 1;
        final int trim_i8_encode = FalconCodec.trim_i8_encode(array2, n, this.CRYPTO_SECRETKEYBYTES - n, array3, this.LOGN, FalconCodec.max_fg_bits[this.LOGN]);
        if (trim_i8_encode == 0) {
            throw new IllegalStateException("f encode failed");
        }
        final byte[] copyOfRange = Arrays.copyOfRange(array2, n, n + trim_i8_encode);
        final int n2 = n + trim_i8_encode;
        final int trim_i8_encode2 = FalconCodec.trim_i8_encode(array2, n2, this.CRYPTO_SECRETKEYBYTES - n2, array4, this.LOGN, FalconCodec.max_fg_bits[this.LOGN]);
        if (trim_i8_encode2 == 0) {
            throw new IllegalStateException("g encode failed");
        }
        final byte[] copyOfRange2 = Arrays.copyOfRange(array2, n2, n2 + trim_i8_encode2);
        final int n3 = n2 + trim_i8_encode2;
        final int trim_i8_encode3 = FalconCodec.trim_i8_encode(array2, n3, this.CRYPTO_SECRETKEYBYTES - n3, array5, this.LOGN, FalconCodec.max_FG_bits[this.LOGN]);
        if (trim_i8_encode3 == 0) {
            throw new IllegalStateException("F encode failed");
        }
        final byte[] copyOfRange3 = Arrays.copyOfRange(array2, n3, n3 + trim_i8_encode3);
        if (n3 + trim_i8_encode3 != this.CRYPTO_SECRETKEYBYTES) {
            throw new IllegalStateException("secret key encoding failed");
        }
        array[0] = (byte)this.LOGN;
        if (FalconCodec.modq_encode(array, this.CRYPTO_PUBLICKEYBYTES - 1, array6, this.LOGN) != this.CRYPTO_PUBLICKEYBYTES - 1) {
            throw new IllegalStateException("public key encoding failed");
        }
        return new byte[][] { Arrays.copyOfRange(array, 1, array.length), copyOfRange, copyOfRange2, copyOfRange3 };
    }
    
    byte[] crypto_sign(final byte[] array, final byte[] array2, final int n, final byte[] array3) {
        final byte[] array4 = new byte[this.N];
        final byte[] array5 = new byte[this.N];
        final byte[] array6 = new byte[this.N];
        final byte[] array7 = new byte[this.N];
        final short[] array8 = new short[this.N];
        final short[] array9 = new short[this.N];
        final byte[] bytes = new byte[48];
        final byte[] bytes2 = new byte[this.NONCELEN];
        final SHAKEDigest shakeDigest = new SHAKEDigest(256);
        final FalconSign falconSign = new FalconSign();
        final int n2 = 0;
        final int trim_i8_decode = FalconCodec.trim_i8_decode(array4, this.LOGN, FalconCodec.max_fg_bits[this.LOGN], array3, 0, this.CRYPTO_SECRETKEYBYTES - n2);
        if (trim_i8_decode == 0) {
            throw new IllegalStateException("f decode failed");
        }
        final int n3 = n2 + trim_i8_decode;
        final int trim_i8_decode2 = FalconCodec.trim_i8_decode(array5, this.LOGN, FalconCodec.max_fg_bits[this.LOGN], array3, n3, this.CRYPTO_SECRETKEYBYTES - n3);
        if (trim_i8_decode2 == 0) {
            throw new IllegalStateException("g decode failed");
        }
        final int n4 = n3 + trim_i8_decode2;
        final int trim_i8_decode3 = FalconCodec.trim_i8_decode(array6, this.LOGN, FalconCodec.max_FG_bits[this.LOGN], array3, n4, this.CRYPTO_SECRETKEYBYTES - n4);
        if (trim_i8_decode3 == 0) {
            throw new IllegalArgumentException("F decode failed");
        }
        if (n4 + trim_i8_decode3 != this.CRYPTO_SECRETKEYBYTES - 1) {
            throw new IllegalStateException("full key not used");
        }
        if (!FalconVrfy.complete_private(array7, array4, array5, array6, this.LOGN, new short[2 * this.N])) {
            throw new IllegalStateException("complete_private failed");
        }
        this.rand.nextBytes(bytes2);
        shakeDigest.update(bytes2, 0, this.NONCELEN);
        shakeDigest.update(array2, 0, n);
        FalconCommon.hash_to_point_vartime(shakeDigest, array9, this.LOGN);
        this.rand.nextBytes(bytes);
        shakeDigest.reset();
        shakeDigest.update(bytes, 0, bytes.length);
        falconSign.sign_dyn(array8, shakeDigest, array4, array5, array6, array7, array9, this.LOGN, new double[10 * this.N]);
        final byte[] array10 = new byte[this.CRYPTO_BYTES - 2 - this.NONCELEN];
        final int comp_encode = FalconCodec.comp_encode(array10, array10.length, array8, this.LOGN);
        if (comp_encode == 0) {
            throw new IllegalStateException("signature failed to generate");
        }
        array[0] = (byte)(48 + this.LOGN);
        System.arraycopy(bytes2, 0, array, 1, this.NONCELEN);
        System.arraycopy(array10, 0, array, 1 + this.NONCELEN, comp_encode);
        return Arrays.copyOfRange(array, 0, 1 + this.NONCELEN + comp_encode);
    }
    
    int crypto_sign_open(final byte[] array, final byte[] array2, final byte[] array3, final byte[] array4) {
        final short[] array5 = new short[this.N];
        final short[] array6 = new short[this.N];
        final short[] array7 = new short[this.N];
        final SHAKEDigest shakeDigest = new SHAKEDigest(256);
        if (FalconCodec.modq_decode(array5, this.LOGN, array4, this.CRYPTO_PUBLICKEYBYTES - 1) != this.CRYPTO_PUBLICKEYBYTES - 1) {
            return -1;
        }
        FalconVrfy.to_ntt_monty(array5, this.LOGN);
        final int length = array.length;
        final int length2 = array3.length;
        if (length < 1 || FalconCodec.comp_decode(array7, this.LOGN, array, length) != length) {
            return -1;
        }
        shakeDigest.update(array2, 0, this.NONCELEN);
        shakeDigest.update(array3, 0, length2);
        FalconCommon.hash_to_point_vartime(shakeDigest, array6, this.LOGN);
        if (FalconVrfy.verify_raw(array6, array7, array5, this.LOGN, new short[this.N]) == 0) {
            return -1;
        }
        return 0;
    }
}
