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

package org.bouncycastle.pqc.crypto.saber;

class Poly
{
    private static final int KARATSUBA_N = 64;
    private static int SCHB_N;
    private final int N_RES;
    private final int N_SB;
    private final int N_SB_RES;
    private final int SABER_N;
    private final int SABER_L;
    private final SABEREngine engine;
    private final Utils utils;
    
    public Poly(final SABEREngine engine) {
        this.engine = engine;
        this.SABER_L = engine.getSABER_L();
        this.SABER_N = engine.getSABER_N();
        this.N_RES = this.SABER_N << 1;
        this.N_SB = this.SABER_N >> 2;
        this.N_SB_RES = 2 * this.N_SB - 1;
        this.utils = engine.getUtils();
    }
    
    public void GenMatrix(final short[][][] array, final byte[] array2) {
        final byte[] array3 = new byte[this.SABER_L * this.engine.getSABER_POLYVECBYTES()];
        this.engine.symmetric.prf(array3, array2, this.engine.getSABER_SEEDBYTES(), array3.length);
        for (int i = 0; i < this.SABER_L; ++i) {
            this.utils.BS2POLVECq(array3, i * this.engine.getSABER_POLYVECBYTES(), array[i]);
        }
    }
    
    public void GenSecret(final short[][] array, final byte[] array2) {
        final byte[] array3 = new byte[this.SABER_L * this.engine.getSABER_POLYCOINBYTES()];
        this.engine.symmetric.prf(array3, array2, this.engine.getSABER_NOISE_SEEDBYTES(), array3.length);
        for (int i = 0; i < this.SABER_L; ++i) {
            if (!this.engine.usingEffectiveMasking) {
                this.cbd(array[i], array3, i * this.engine.getSABER_POLYCOINBYTES());
            }
            else {
                for (int j = 0; j < this.SABER_N / 4; ++j) {
                    array[i][4 * j] = (short)(((array3[j + i * this.engine.getSABER_POLYCOINBYTES()] & 0x3) ^ 0x2) - 2);
                    array[i][4 * j + 1] = (short)(((array3[j + i * this.engine.getSABER_POLYCOINBYTES()] >>> 2 & 0x3) ^ 0x2) - 2);
                    array[i][4 * j + 2] = (short)(((array3[j + i * this.engine.getSABER_POLYCOINBYTES()] >>> 4 & 0x3) ^ 0x2) - 2);
                    array[i][4 * j + 3] = (short)(((array3[j + i * this.engine.getSABER_POLYCOINBYTES()] >>> 6 & 0x3) ^ 0x2) - 2);
                }
            }
        }
    }
    
    private long load_littleendian(final byte[] array, final int n, final int n2) {
        long n3 = array[n + 0] & 0xFF;
        for (int i = 1; i < n2; ++i) {
            n3 |= (long)(array[n + i] & 0xFF) << 8 * i;
        }
        return n3;
    }
    
    private void cbd(final short[] array, final byte[] array2, final int n) {
        final int[] array3 = new int[4];
        final int[] array4 = new int[4];
        if (this.engine.getSABER_MU() == 6) {
            for (int i = 0; i < this.SABER_N / 4; ++i) {
                final int n2 = (int)this.load_littleendian(array2, n + 3 * i, 3);
                int n3 = 0;
                for (int j = 0; j < 3; ++j) {
                    n3 += (n2 >> j & 0x249249);
                }
                array3[0] = (n3 & 0x7);
                array4[0] = (n3 >>> 3 & 0x7);
                array3[1] = (n3 >>> 6 & 0x7);
                array4[1] = (n3 >>> 9 & 0x7);
                array3[2] = (n3 >>> 12 & 0x7);
                array4[2] = (n3 >>> 15 & 0x7);
                array3[3] = (n3 >>> 18 & 0x7);
                array4[3] = n3 >>> 21;
                array[4 * i + 0] = (short)(array3[0] - array4[0]);
                array[4 * i + 1] = (short)(array3[1] - array4[1]);
                array[4 * i + 2] = (short)(array3[2] - array4[2]);
                array[4 * i + 3] = (short)(array3[3] - array4[3]);
            }
        }
        else if (this.engine.getSABER_MU() == 8) {
            for (int k = 0; k < this.SABER_N / 4; ++k) {
                final int n4 = (int)this.load_littleendian(array2, n + 4 * k, 4);
                int n5 = 0;
                for (int l = 0; l < 4; ++l) {
                    n5 += (n4 >>> l & 0x11111111);
                }
                array3[0] = (n5 & 0xF);
                array4[0] = (n5 >>> 4 & 0xF);
                array3[1] = (n5 >>> 8 & 0xF);
                array4[1] = (n5 >>> 12 & 0xF);
                array3[2] = (n5 >>> 16 & 0xF);
                array4[2] = (n5 >>> 20 & 0xF);
                array3[3] = (n5 >>> 24 & 0xF);
                array4[3] = n5 >>> 28;
                array[4 * k + 0] = (short)(array3[0] - array4[0]);
                array[4 * k + 1] = (short)(array3[1] - array4[1]);
                array[4 * k + 2] = (short)(array3[2] - array4[2]);
                array[4 * k + 3] = (short)(array3[3] - array4[3]);
            }
        }
        else if (this.engine.getSABER_MU() == 10) {
            for (int n6 = 0; n6 < this.SABER_N / 4; ++n6) {
                final long load_littleendian = this.load_littleendian(array2, n + 5 * n6, 5);
                long n7 = 0L;
                for (int n8 = 0; n8 < 5; ++n8) {
                    n7 += (load_littleendian >>> n8 & 0x842108421L);
                }
                array3[0] = (int)(n7 & 0x1FL);
                array4[0] = (int)(n7 >>> 5 & 0x1FL);
                array3[1] = (int)(n7 >>> 10 & 0x1FL);
                array4[1] = (int)(n7 >>> 15 & 0x1FL);
                array3[2] = (int)(n7 >>> 20 & 0x1FL);
                array4[2] = (int)(n7 >>> 25 & 0x1FL);
                array3[3] = (int)(n7 >>> 30 & 0x1FL);
                array4[3] = (int)(n7 >>> 35);
                array[4 * n6 + 0] = (short)(array3[0] - array4[0]);
                array[4 * n6 + 1] = (short)(array3[1] - array4[1]);
                array[4 * n6 + 2] = (short)(array3[2] - array4[2]);
                array[4 * n6 + 3] = (short)(array3[3] - array4[3]);
            }
        }
    }
    
    private short OVERFLOWING_MUL(final int n, final int n2) {
        return (short)(n * n2);
    }
    
    private void karatsuba_simple(final int[] array, final int[] array2, final int[] array3) {
        final int[] array4 = new int[31];
        final int[] array5 = new int[31];
        final int[] array6 = new int[31];
        final int[] array7 = new int[63];
        for (int i = 0; i < 16; ++i) {
            final int n = array[i];
            final int n2 = array[i + 16];
            final int n3 = array[i + 32];
            final int n4 = array[i + 48];
            for (int j = 0; j < 16; ++j) {
                final int n5 = array2[j];
                final int n6 = array2[j + 16];
                array3[i + j + 0] += this.OVERFLOWING_MUL(n, n5);
                array3[i + j + 32] += this.OVERFLOWING_MUL(n2, n6);
                array4[i + j] += (int)((n5 + n6) * (long)(n + n2));
                final int n7 = array2[j + 32];
                final int n8 = array2[j + 48];
                array3[i + j + 64] += this.OVERFLOWING_MUL(n7, n3);
                array3[i + j + 96] += this.OVERFLOWING_MUL(n8, n4);
                array6[i + j] += this.OVERFLOWING_MUL(n3 + n4, n7 + n8);
                final int n9 = n5 + n7;
                final int n10 = n + n3;
                array7[i + j + 0] += this.OVERFLOWING_MUL(n9, n10);
                final int n11 = n6 + n8;
                final int n12 = n2 + n4;
                array7[i + j + 32] += this.OVERFLOWING_MUL(n11, n12);
                array5[i + j] += this.OVERFLOWING_MUL(n9 + n11, n10 + n12);
            }
        }
        for (int k = 0; k < 31; ++k) {
            array5[k] = array5[k] - array7[k + 0] - array7[k + 32];
            array4[k] = array4[k] - array3[k + 0] - array3[k + 32];
            array6[k] = array6[k] - array3[k + 64] - array3[k + 96];
        }
        for (int l = 0; l < 31; ++l) {
            array7[l + 16] += array5[l];
            array3[l + 16] += array4[l];
            array3[l + 80] += array6[l];
        }
        for (int n13 = 0; n13 < 63; ++n13) {
            array7[n13] = array7[n13] - array3[n13] - array3[n13 + 64];
        }
        for (int n14 = 0; n14 < 63; ++n14) {
            array3[n14 + 32] += array7[n14];
        }
    }
    
    private void toom_cook_4way(final short[] array, final short[] array2, final short[] array3) {
        final int n = 43691;
        final int n2 = 36409;
        final int n3 = 61167;
        final int[] array4 = new int[this.N_SB];
        final int[] array5 = new int[this.N_SB];
        final int[] array6 = new int[this.N_SB];
        final int[] array7 = new int[this.N_SB];
        final int[] array8 = new int[this.N_SB];
        final int[] array9 = new int[this.N_SB];
        final int[] array10 = new int[this.N_SB];
        final int[] array11 = new int[this.N_SB];
        final int[] array12 = new int[this.N_SB];
        final int[] array13 = new int[this.N_SB];
        final int[] array14 = new int[this.N_SB];
        final int[] array15 = new int[this.N_SB];
        final int[] array16 = new int[this.N_SB];
        final int[] array17 = new int[this.N_SB];
        final int[] array18 = new int[this.N_SB_RES];
        final int[] array19 = new int[this.N_SB_RES];
        final int[] array20 = new int[this.N_SB_RES];
        final int[] array21 = new int[this.N_SB_RES];
        final int[] array22 = new int[this.N_SB_RES];
        final int[] array23 = new int[this.N_SB_RES];
        final int[] array24 = new int[this.N_SB_RES];
        for (int i = 0; i < this.N_SB; ++i) {
            final short n4 = array[i];
            final short n5 = array[i + this.N_SB];
            final short n6 = array[i + this.N_SB * 2];
            final short n7 = array[i + this.N_SB * 3];
            final short n8 = (short)(n4 + n6);
            final short n9 = (short)(n5 + n7);
            final short n10 = (short)(n8 + n9);
            final short n11 = (short)(n8 - n9);
            array6[i] = n10;
            array7[i] = n11;
            final short n12 = (short)((n4 << 2) + n6 << 1);
            final short n13 = (short)((n5 << 2) + n7);
            final short n14 = (short)(n12 + n13);
            final short n15 = (short)(n12 - n13);
            array8[i] = n14;
            array9[i] = n15;
            array5[i] = (short)((n7 << 3) + (n6 << 2) + (n5 << 1) + n4);
            array10[i] = n4;
            array4[i] = n7;
        }
        for (int j = 0; j < this.N_SB; ++j) {
            final short n16 = array2[j];
            final short n17 = array2[j + this.N_SB];
            final short n18 = array2[j + this.N_SB * 2];
            final short n19 = array2[j + this.N_SB * 3];
            final int n20 = n16 + n18;
            final int n21 = n17 + n19;
            final int n22 = n20 + n21;
            final int n23 = n20 - n21;
            array13[j] = n22;
            array14[j] = n23;
            final int n24 = (n16 << 2) + n18 << 1;
            final int n25 = (n17 << 2) + n19;
            final int n26 = n24 + n25;
            final int n27 = n24 - n25;
            array15[j] = n26;
            array16[j] = n27;
            array12[j] = (n19 << 3) + (n18 << 2) + (n17 << 1) + n16;
            array17[j] = n16;
            array11[j] = n19;
        }
        this.karatsuba_simple(array4, array11, array18);
        this.karatsuba_simple(array5, array12, array19);
        this.karatsuba_simple(array6, array13, array20);
        this.karatsuba_simple(array7, array14, array21);
        this.karatsuba_simple(array8, array15, array22);
        this.karatsuba_simple(array9, array16, array23);
        this.karatsuba_simple(array10, array17, array24);
        for (int k = 0; k < this.N_SB_RES; ++k) {
            final int n28 = array18[k];
            final int n29 = array19[k];
            final int n30 = array20[k];
            final int n31 = array21[k];
            final int n32 = array22[k];
            final int n33 = array23[k];
            final int n34 = array24[k];
            final int n35 = n29 + n32;
            final int n36 = n33 - n32;
            final int n37 = (n31 & 0xFFFF) - (n30 & 0xFFFF) >>> 1;
            final int n38 = (n32 - n28 - (n34 << 6) << 1) + n36;
            final int n39 = n30 + n37;
            final int n40 = n35 - (n39 << 6) - n39;
            final int n41 = n39 - n34 - n28;
            final int n42 = n40 + 45 * n41;
            final int n43 = ((n38 & 0xFFFF) - (n41 << 3)) * n >> 3;
            final int n44 = n36 + n42;
            final int n45 = ((n42 & 0xFFFF) + ((n37 & 0xFFFF) << 4)) * n2 >> 1;
            final int n46 = -(n37 + n45);
            final int n47 = (30 * (n45 & 0xFFFF) - (n44 & 0xFFFF)) * n3 >> 2;
            final int n48 = n41 - n43;
            final int n49 = n45 - n47;
            final int n50 = k;
            array3[n50] += (short)(n34 & 0xFFFF);
            final int n51 = k + 64;
            array3[n51] += (short)(n47 & 0xFFFF);
            final int n52 = k + 128;
            array3[n52] += (short)(n43 & 0xFFFF);
            final int n53 = k + 192;
            array3[n53] += (short)(n46 & 0xFFFF);
            final int n54 = k + 256;
            array3[n54] += (short)(n48 & 0xFFFF);
            final int n55 = k + 320;
            array3[n55] += (short)(n49 & 0xFFFF);
            final int n56 = k + 384;
            array3[n56] += (short)(n28 & 0xFFFF);
        }
    }
    
    private void poly_mul_acc(final short[] array, final short[] array2, final short[] array3) {
        final short[] array4 = new short[2 * this.SABER_N];
        this.toom_cook_4way(array, array2, array4);
        for (int i = this.SABER_N; i < 2 * this.SABER_N; ++i) {
            final int n = i - this.SABER_N;
            array3[n] += (short)(array4[i - this.SABER_N] - array4[i]);
        }
    }
    
    public void MatrixVectorMul(final short[][][] array, final short[][] array2, final short[][] array3, final int n) {
        for (int i = 0; i < this.SABER_L; ++i) {
            for (int j = 0; j < this.SABER_L; ++j) {
                if (n == 1) {
                    this.poly_mul_acc(array[j][i], array2[j], array3[i]);
                }
                else {
                    this.poly_mul_acc(array[i][j], array2[j], array3[i]);
                }
            }
        }
    }
    
    public void InnerProd(final short[][] array, final short[][] array2, final short[] array3) {
        for (int i = 0; i < this.SABER_L; ++i) {
            this.poly_mul_acc(array[i], array2[i], array3);
        }
    }
    
    static {
        Poly.SCHB_N = 16;
    }
}
