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

package org.bouncycastle.pqc.crypto.saber;

import org.bouncycastle.util.Arrays;
import java.security.SecureRandom;

class SABEREngine
{
    public static final int SABER_EP = 10;
    public static final int SABER_N = 256;
    private static final int SABER_SEEDBYTES = 32;
    private static final int SABER_NOISE_SEEDBYTES = 32;
    private static final int SABER_KEYBYTES = 32;
    private static final int SABER_HASHBYTES = 32;
    private final int SABER_L;
    private final int SABER_MU;
    private final int SABER_ET;
    private final int SABER_POLYCOINBYTES;
    private final int SABER_EQ;
    private final int SABER_POLYBYTES;
    private final int SABER_POLYVECBYTES;
    private final int SABER_POLYCOMPRESSEDBYTES;
    private final int SABER_POLYVECCOMPRESSEDBYTES;
    private final int SABER_SCALEBYTES_KEM;
    private final int SABER_INDCPA_PUBLICKEYBYTES;
    private final int SABER_INDCPA_SECRETKEYBYTES;
    private final int SABER_PUBLICKEYBYTES;
    private final int SABER_SECRETKEYBYTES;
    private final int SABER_BYTES_CCA_DEC;
    private final int defaultKeySize;
    private final int h1;
    private final int h2;
    private final Utils utils;
    private final Poly poly;
    private final boolean usingAES;
    protected final boolean usingEffectiveMasking;
    protected final Symmetric symmetric;
    
    public int getSABER_N() {
        return 256;
    }
    
    public int getSABER_EP() {
        return 10;
    }
    
    public int getSABER_KEYBYTES() {
        return 32;
    }
    
    public int getSABER_L() {
        return this.SABER_L;
    }
    
    public int getSABER_ET() {
        return this.SABER_ET;
    }
    
    public int getSABER_POLYBYTES() {
        return this.SABER_POLYBYTES;
    }
    
    public int getSABER_POLYVECBYTES() {
        return this.SABER_POLYVECBYTES;
    }
    
    public int getSABER_SEEDBYTES() {
        return 32;
    }
    
    public int getSABER_POLYCOINBYTES() {
        return this.SABER_POLYCOINBYTES;
    }
    
    public int getSABER_NOISE_SEEDBYTES() {
        return 32;
    }
    
    public int getSABER_MU() {
        return this.SABER_MU;
    }
    
    public Utils getUtils() {
        return this.utils;
    }
    
    public int getSessionKeySize() {
        return this.defaultKeySize / 8;
    }
    
    public int getCipherTextSize() {
        return this.SABER_BYTES_CCA_DEC;
    }
    
    public int getPublicKeySize() {
        return this.SABER_PUBLICKEYBYTES;
    }
    
    public int getPrivateKeySize() {
        return this.SABER_SECRETKEYBYTES;
    }
    
    public SABEREngine(final int saber_L, final int defaultKeySize, final boolean usingAES, final boolean usingEffectiveMasking) {
        this.defaultKeySize = defaultKeySize;
        this.usingAES = usingAES;
        this.usingEffectiveMasking = usingEffectiveMasking;
        this.SABER_L = saber_L;
        if (saber_L == 2) {
            this.SABER_MU = 10;
            this.SABER_ET = 3;
        }
        else if (saber_L == 3) {
            this.SABER_MU = 8;
            this.SABER_ET = 4;
        }
        else {
            this.SABER_MU = 6;
            this.SABER_ET = 6;
        }
        if (usingAES) {
            this.symmetric = new Symmetric.AesSymmetric();
        }
        else {
            this.symmetric = new Symmetric.ShakeSymmetric();
        }
        if (usingEffectiveMasking) {
            this.SABER_EQ = 12;
            this.SABER_POLYCOINBYTES = 64;
        }
        else {
            this.SABER_EQ = 13;
            this.SABER_POLYCOINBYTES = this.SABER_MU * 256 / 8;
        }
        this.SABER_POLYBYTES = this.SABER_EQ * 256 / 8;
        this.SABER_POLYVECBYTES = this.SABER_L * this.SABER_POLYBYTES;
        this.SABER_POLYCOMPRESSEDBYTES = 320;
        this.SABER_POLYVECCOMPRESSEDBYTES = this.SABER_L * this.SABER_POLYCOMPRESSEDBYTES;
        this.SABER_SCALEBYTES_KEM = this.SABER_ET * 256 / 8;
        this.SABER_INDCPA_PUBLICKEYBYTES = this.SABER_POLYVECCOMPRESSEDBYTES + 32;
        this.SABER_INDCPA_SECRETKEYBYTES = this.SABER_POLYVECBYTES;
        this.SABER_PUBLICKEYBYTES = this.SABER_INDCPA_PUBLICKEYBYTES;
        this.SABER_SECRETKEYBYTES = this.SABER_INDCPA_SECRETKEYBYTES + this.SABER_INDCPA_PUBLICKEYBYTES + 32 + 32;
        this.SABER_BYTES_CCA_DEC = this.SABER_POLYVECCOMPRESSEDBYTES + this.SABER_SCALEBYTES_KEM;
        this.h1 = 1 << this.SABER_EQ - 10 - 1;
        this.h2 = 256 - (1 << 10 - this.SABER_ET - 1) + (1 << this.SABER_EQ - 10 - 1);
        this.utils = new Utils(this);
        this.poly = new Poly(this);
    }
    
    private void indcpa_kem_keypair(final byte[] array, final byte[] array2, final SecureRandom secureRandom) {
        final short[][][] array3 = new short[this.SABER_L][this.SABER_L][256];
        final short[][] array4 = new short[this.SABER_L][256];
        final short[][] array5 = new short[this.SABER_L][256];
        final byte[] bytes = new byte[32];
        final byte[] bytes2 = new byte[32];
        secureRandom.nextBytes(bytes);
        this.symmetric.prf(bytes, bytes, 32, 32);
        secureRandom.nextBytes(bytes2);
        this.poly.GenMatrix(array3, bytes);
        this.poly.GenSecret(array4, bytes2);
        this.poly.MatrixVectorMul(array3, array4, array5, 1);
        for (int i = 0; i < this.SABER_L; ++i) {
            for (int j = 0; j < 256; ++j) {
                array5[i][j] = (short)((array5[i][j] + this.h1 & 0xFFFF) >>> this.SABER_EQ - 10);
            }
        }
        this.utils.POLVECq2BS(array2, array4);
        this.utils.POLVECp2BS(array, array5);
        System.arraycopy(bytes, 0, array, this.SABER_POLYVECCOMPRESSEDBYTES, bytes.length);
    }
    
    public int crypto_kem_keypair(final byte[] array, final byte[] array2, final SecureRandom secureRandom) {
        this.indcpa_kem_keypair(array, array2, secureRandom);
        for (int i = 0; i < this.SABER_INDCPA_PUBLICKEYBYTES; ++i) {
            array2[i + this.SABER_INDCPA_SECRETKEYBYTES] = array[i];
        }
        this.symmetric.hash_h(array2, array, this.SABER_SECRETKEYBYTES - 64);
        final byte[] bytes = new byte[32];
        secureRandom.nextBytes(bytes);
        System.arraycopy(bytes, 0, array2, this.SABER_SECRETKEYBYTES - 32, bytes.length);
        return 0;
    }
    
    private void indcpa_kem_enc(final byte[] array, final byte[] array2, final byte[] array3, final byte[] array4) {
        final short[][][] array5 = new short[this.SABER_L][this.SABER_L][256];
        final short[][] array6 = new short[this.SABER_L][256];
        final short[][] array7 = new short[this.SABER_L][256];
        final short[][] array8 = new short[this.SABER_L][256];
        final short[] array9 = new short[256];
        final short[] array10 = new short[256];
        this.poly.GenMatrix(array5, Arrays.copyOfRange(array3, this.SABER_POLYVECCOMPRESSEDBYTES, array3.length));
        this.poly.GenSecret(array6, array2);
        this.poly.MatrixVectorMul(array5, array6, array7, 0);
        for (int i = 0; i < this.SABER_L; ++i) {
            for (int j = 0; j < 256; ++j) {
                array7[i][j] = (short)((array7[i][j] + this.h1 & 0xFFFF) >>> this.SABER_EQ - 10);
            }
        }
        this.utils.POLVECp2BS(array4, array7);
        this.utils.BS2POLVECp(array3, array8);
        this.poly.InnerProd(array8, array6, array10);
        this.utils.BS2POLmsg(array, array9);
        for (int k = 0; k < 256; ++k) {
            array10[k] = (short)((array10[k] - (array9[k] << 9) + this.h1 & 0xFFFF) >>> 10 - this.SABER_ET);
        }
        this.utils.POLT2BS(array4, this.SABER_POLYVECCOMPRESSEDBYTES, array10);
    }
    
    public int crypto_kem_enc(final byte[] array, final byte[] array2, final byte[] array3, final SecureRandom secureRandom) {
        final byte[] array4 = new byte[64];
        final byte[] array5 = new byte[64];
        final byte[] bytes = new byte[32];
        secureRandom.nextBytes(bytes);
        this.symmetric.hash_h(bytes, bytes, 0);
        System.arraycopy(bytes, 0, array5, 0, 32);
        this.symmetric.hash_h(array5, array3, 32);
        this.symmetric.hash_g(array4, array5);
        this.indcpa_kem_enc(array5, Arrays.copyOfRange(array4, 32, array4.length), array3, array);
        this.symmetric.hash_h(array4, array, 32);
        final byte[] array6 = new byte[32];
        this.symmetric.hash_h(array6, array4, 0);
        System.arraycopy(array6, 0, array2, 0, this.defaultKeySize / 8);
        return 0;
    }
    
    private void indcpa_kem_dec(final byte[] array, final byte[] array2, final byte[] array3) {
        final short[][] array4 = new short[this.SABER_L][256];
        final short[][] array5 = new short[this.SABER_L][256];
        final short[] array6 = new short[256];
        final short[] array7 = new short[256];
        this.utils.BS2POLVECq(array, 0, array4);
        this.utils.BS2POLVECp(array2, array5);
        this.poly.InnerProd(array5, array4, array6);
        this.utils.BS2POLT(array2, this.SABER_POLYVECCOMPRESSEDBYTES, array7);
        for (int i = 0; i < 256; ++i) {
            array6[i] = (short)((array6[i] + this.h2 - (array7[i] << 10 - this.SABER_ET) & 0xFFFF) >> 9);
        }
        this.utils.POLmsg2BS(array3, array6);
    }
    
    public int crypto_kem_dec(final byte[] array, final byte[] array2, final byte[] array3) {
        final byte[] array4 = new byte[this.SABER_BYTES_CCA_DEC];
        final byte[] array5 = new byte[64];
        final byte[] array6 = new byte[64];
        final byte[] copyOfRange = Arrays.copyOfRange(array3, this.SABER_INDCPA_SECRETKEYBYTES, array3.length);
        this.indcpa_kem_dec(array3, array2, array5);
        for (int i = 0; i < 32; ++i) {
            array5[32 + i] = array3[this.SABER_SECRETKEYBYTES - 64 + i];
        }
        this.symmetric.hash_g(array6, array5);
        this.indcpa_kem_enc(array5, Arrays.copyOfRange(array6, 32, array6.length), copyOfRange, array4);
        final int verify = verify(array2, array4, this.SABER_BYTES_CCA_DEC);
        this.symmetric.hash_h(array6, array2, 32);
        cmov(array6, array3, this.SABER_SECRETKEYBYTES - 32, 32, (byte)verify);
        final byte[] array7 = new byte[32];
        this.symmetric.hash_h(array7, array6, 0);
        System.arraycopy(array7, 0, array, 0, this.defaultKeySize / 8);
        return 0;
    }
    
    static int verify(final byte[] array, final byte[] array2, final int n) {
        long n2 = 0L;
        for (int i = 0; i < n; ++i) {
            n2 |= (array[i] ^ array2[i]);
        }
        return (int)(-n2 >>> 63);
    }
    
    static void cmov(final byte[] array, final byte[] array2, final int n, final int n2, final byte b) {
        final byte b2 = (byte)(-b);
        for (int i = 0; i < n2; ++i) {
            final int n3 = i;
            array[n3] ^= (byte)(b2 & (array2[i + n] ^ array[i]));
        }
    }
}
